// This file defines templates for transforming Modelica/MetaModelica code to C
// code. They are used in the code generator phase of the compiler to write
// target code.
//
// There are two root templates intended to be called from the code generator:
// translateModel and translateFunctions. These templates do not return any
// result but instead write the result to files. All other templates return
// text and are used by the root templates (most of them indirectly).
//
// To future maintainers of this file:
//
// - A line like this
//     # var = ""
//   declares a text buffer that you can later append text to. It can also be
//   passed to other templates that in turn can append text to it. In the new
//   version of Susan it should be written like this instead:
//     let &var = buffer ""
//
// - A line like this
//     ..., Text var, ...
//   declares that a template takes a tmext buffer as input parameter. In the
//   new version of Susan it should be written like this instead:
//     ..., Text &var, ...
//
// - A line like this:
//     ..., var, ...
//   passes a text buffer to a template. In the new version of Susan it should
//   be written like this instead:
//     ..., &var, ...
//
// - Style guidelines:
//
//   - Try (hard) to limit each row to 80 characters
//
//   - Code for a template should be indented with 2 spaces
//
//     - Exception to this rule is if you have only a single case, then that
//       single case can be written using no indentation
//
//       This single case can be seen as a clarification of the input to the
//       template
//
//   - Code after a case should be indented with 2 spaces if not written on the
//     same line

package CodegenC

import interface SimCodeTV;
import interface SimCodeBackendTV;
import CodegenUtil.*;
import CodegenUtilSimulation.*;
import CodegenCFunctions.*;
import ExpressionDumpTpl.*;

/* public */ template translateModel(SimCode simCode)
  "Generates C code and Makefile for compiling and running a simulation of a
  Modelica model.
  used in Compiler/SimCode/SimCodeMain.mo"
::=
  match simCode
  case sc as SIMCODE(modelInfo=modelInfo as MODELINFO(__)) then
    let()= System.tmpTickResetIndex(0,2) /* auxFunction index */
    let()= System.tmpTickResetIndex(0,20)  /*parfor index*/

    let &literalsFile = buffer ""
    let &literalsFile += redirectToFile('<%fileNamePrefix%>_literals.h')
    let &literalsFile += simulationLiteralsFile(fileNamePrefix, literals)
    let &literalsFile += closeFile()

    let &functionsHeader = buffer ""
    let &functionsHeader += redirectToFile('<%fileNamePrefix%>_functions.h')
    let &functionsHeader += simulationFunctionsHeaderFile(fileNamePrefix, modelInfo.functions, recordDecls, sc.generic_loop_calls)
    let &functionsHeader += closeFile()

    let &includes = buffer ""
    let &includes += redirectToFile('<%fileNamePrefix%>_includes.h')
    let &includes += externalFunctionIncludes(sc.externalFunctionIncludes)
    let &includes += closeFile()

    let &records = buffer ""
    let &records += redirectToFile('<%fileNamePrefix%>_records.c')
    let &records += recordsFile(fileNamePrefix, recordDecls, true /*isSimulation*/)
    let &records += closeFile()

    // adpro: write the main .c file last! Make on windows does not seem to realize that
    //        the .c file is newer than the .o file if we have succesive simulate commands
    //        for the same model (i.e. see testsuite/linearize/simextfunction.mos).

    // If ParModelica generate the kernels file too.
    if acceptParModelicaGrammar() then
      let &cl = buffer ""
      let &cl += redirectToFile('<%fileNamePrefix%>_kernels.cl')
      let &cl += simulationParModelicaKernelsFile(fileNamePrefix, modelInfo.functions)
      let &cl += closeFile()
      ""

    //this top-level template always returns an empty result
    //since generated texts are written to files directly
  end match
end translateModel;

/* public */ template simulationHeaderFile(SimCode simCode)
  "Generates code for main C file for simulation target.
   used in Compiler/Template/CodegenFMU.tpl"
::=
  let modelNamePrefixStr = modelNamePrefix(simCode)
  match simCode
  case simCode as SIMCODE(modelInfo=MODELINFO(functions=functions, varInfo=varInfo as VARINFO(__))) then
    <<
    /* Simulation code for <%dotPath(modelInfo.name)%> generated by the OpenModelica Compiler <%getVersionNr()%>. */
    #if !defined(<%modelNamePrefixStr%>__MODEL_H)
    #define <%modelNamePrefixStr%>__MODEL_H

    #include "openmodelica.h"
    #include "openmodelica_func.h"
    #include "simulation_data.h"
    #include "simulation/simulation_info_json.h"
    #include "simulation/simulation_runtime.h"
    #include "util/omc_error.h"
    #include "util/parallel_helper.h"
    #include "simulation/jacobian_util.h"
    #include "simulation/simulation_omc_assert.h"
    #include "simulation/solver/model_help.h"
    #include "simulation/solver/delay.h"
    #include "simulation/solver/linearSystem.h"
    #include "simulation/solver/nonlinearSystem.h"
    #include "simulation/solver/mixedSystem.h"
    #include "simulation/solver/spatialDistribution.h"

    #if defined(__cplusplus)
    extern "C" {
    #endif

    #include <string.h>

    #include "<%fileNamePrefix%>_functions.h"

    <%variableDefinitions(modelInfo, timeEvents)%><%functions |> fn hasindex i0 => '#define <%functionName(fn,false)%>_index <%i0%>'; separator="\n"%>

    extern void <%symbolName(modelNamePrefixStr,"callExternalObjectDestructors")%>(DATA *_data, threadData_t *threadData);
    #if !defined(OMC_NUM_NONLINEAR_SYSTEMS) || OMC_NUM_NONLINEAR_SYSTEMS>0
    <% if intGt(varInfo.numNonLinearSystems, 0) then 'extern void <%symbolName(modelNamePrefixStr,"initialNonLinearSystem")%>(int nNonLinearSystems, NONLINEAR_SYSTEM_DATA *data);' %>
    #endif
    #if !defined(OMC_NUM_LINEAR_SYSTEMS) || OMC_NUM_LINEAR_SYSTEMS>0
    <% if intGt(varInfo.numLinearSystems, 0) then 'extern void <%symbolName(modelNamePrefixStr,"initialLinearSystem")%>(int nLinearSystems, LINEAR_SYSTEM_DATA *data);' %>
    #endif
    #if !defined(OMC_NUM_MIXED_SYSTEMS) || OMC_NUM_MIXED_SYSTEMS>0
    <% if intGt(varInfo.numMixedSystems, 0) then 'extern void <%symbolName(modelNamePrefixStr,"initialMixedSystem")%>(int nMixedSystems, MIXED_SYSTEM_DATA *data);' %>
    #endif
    #if !defined(OMC_NO_STATESELECTION)
    extern void <%symbolName(modelNamePrefixStr,"initializeStateSets")%>(int nStateSets, STATE_SET_DATA* statesetData, DATA *data);
    #endif
    extern int <%symbolName(modelNamePrefixStr,"functionAlgebraics")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"function_storeDelayed")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"function_storeSpatialDistribution")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"function_initSpatialDistribution")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"updateBoundVariableAttributes")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"functionInitialEquations")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"functionInitialEquations_lambda0")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"functionRemovedInitialEquations")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"updateBoundParameters")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"checkForAsserts")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"function_ZeroCrossingsEquations")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"function_ZeroCrossings")%>(DATA *data, threadData_t *threadData, double* gout);
    extern int <%symbolName(modelNamePrefixStr,"function_updateRelations")%>(DATA *data, threadData_t *threadData, int evalZeroCross);
    extern const char* <%symbolName(modelNamePrefixStr,"zeroCrossingDescription")%>(int i, int **out_EquationIndexes);
    extern const char* <%symbolName(modelNamePrefixStr,"relationDescription")%>(int i);
    extern void <%symbolName(modelNamePrefixStr,"function_initSample")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"initialAnalyticJacobianG")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian);
    extern int <%symbolName(modelNamePrefixStr,"initialAnalyticJacobianA")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian);
    extern int <%symbolName(modelNamePrefixStr,"initialAnalyticJacobianB")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian);
    extern int <%symbolName(modelNamePrefixStr,"initialAnalyticJacobianC")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian);
    extern int <%symbolName(modelNamePrefixStr,"initialAnalyticJacobianD")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian);
    extern int <%symbolName(modelNamePrefixStr,"initialAnalyticJacobianF")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian);
    extern int <%symbolName(modelNamePrefixStr,"initialAnalyticJacobianH")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian);
    extern int <%symbolName(modelNamePrefixStr,"functionJacG_column")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *thisJacobian, ANALYTIC_JACOBIAN *parentJacobian);
    extern int <%symbolName(modelNamePrefixStr,"functionJacA_column")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *thisJacobian, ANALYTIC_JACOBIAN *parentJacobian);
    extern int <%symbolName(modelNamePrefixStr,"functionJacB_column")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *thisJacobian, ANALYTIC_JACOBIAN *parentJacobian);
    extern int <%symbolName(modelNamePrefixStr,"functionJacC_column")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *thisJacobian, ANALYTIC_JACOBIAN *parentJacobian);
    extern int <%symbolName(modelNamePrefixStr,"functionJacD_column")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *thisJacobian, ANALYTIC_JACOBIAN *parentJacobian);
    extern int <%symbolName(modelNamePrefixStr,"functionJacF_column")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *thisJacobian, ANALYTIC_JACOBIAN *parentJacobian);
    extern int <%symbolName(modelNamePrefixStr,"functionJacH_column")%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *thisJacobian, ANALYTIC_JACOBIAN *parentJacobian);
    extern const char* <%symbolName(modelNamePrefixStr,"linear_model_frame")%>(void);
    extern const char* <%symbolName(modelNamePrefixStr,"linear_model_datarecovery_frame")%>(void);
    extern int <%symbolName(modelNamePrefixStr,"mayer")%>(DATA* data, modelica_real** res, short *);
    extern int <%symbolName(modelNamePrefixStr,"lagrange")%>(DATA* data, modelica_real** res, short *, short *);
    extern int <%symbolName(modelNamePrefixStr,"pickUpBoundsForInputsInOptimization")%>(DATA* data, modelica_real* min, modelica_real* max, modelica_real*nominal, modelica_boolean *useNominal, char ** name, modelica_real * start, modelica_real * startTimeOpt);
    extern int <%symbolName(modelNamePrefixStr,"setInputData")%>(DATA *data, const modelica_boolean file);
    extern int <%symbolName(modelNamePrefixStr,"getTimeGrid")%>(DATA *data, modelica_integer * nsi, modelica_real**t);
    extern void <%symbolName(modelNamePrefixStr,"function_initSynchronous")%>(DATA * data, threadData_t *threadData);
    extern void <%symbolName(modelNamePrefixStr,"function_updateSynchronous")%>(DATA * data, threadData_t *threadData, long base_idx);
    extern int <%symbolName(modelNamePrefixStr,"function_equationsSynchronous")%>(DATA * data, threadData_t *threadData, long base_idx, long sub_idx);
    extern void <%symbolName(modelNamePrefixStr,"read_simulation_info")%>(SIMULATION_INFO* simulationData);
    extern void <%symbolName(modelNamePrefixStr,"read_input_fmu")%>(MODEL_DATA* modelData);
    extern void <%symbolName(modelNamePrefixStr,"function_savePreSynchronous")%>(DATA *data, threadData_t *threadData);
    extern int <%symbolName(modelNamePrefixStr,"inputNames")%>(DATA* data, char ** names);
    extern int <%symbolName(modelNamePrefixStr,"dataReconciliationInputNames")%>(DATA* data, char ** names);
    extern int <%symbolName(modelNamePrefixStr,"dataReconciliationUnmeasuredVariables")%>(DATA* data, char ** names);
    extern int <%symbolName(modelNamePrefixStr,"initializeDAEmodeData")%>(DATA *data, DAEMODE_DATA*);
    extern int <%symbolName(modelNamePrefixStr,"functionLocalKnownVars")%>(DATA* data, threadData_t* threadData);
    extern int <%symbolName(modelNamePrefixStr,"symbolicInlineSystem")%>(DATA* data, threadData_t* threadData);

    #include "<%fileNamePrefix%>_literals.h"

    <%if Flags.getConfigBool(Flags.PARMODAUTO) then "#include \"ParModelica/auto/om_pm_interface.hpp\""%>

    <%if stringEq(getConfigString(HPCOM_CODE),"pthreads_spin") then "#include \"util/omc_spinlock.h\""%>

    <%if Flags.isSet(HPCOM) then "#define HPCOM"%>

    #if defined(HPCOM) && !defined(_OPENMP)
      #error "HPCOM requires OpenMP or the results are wrong"
    #endif
    #if defined(_OPENMP)
      #include <omp.h>
    #else
      /* dummy omp defines */
      #define omp_get_max_threads() 1
    #endif

    #if defined(__cplusplus)
    }
    #endif

    #endif /* !defined(<%modelNamePrefixStr%>__MODEL_H) */

    <%\n%>
    >>
  end match
end simulationHeaderFile;

template simulationFile_mixAndHeader(SimCode simCode, String modelNamePrefix)
::=
  let &mixheader = buffer ""
  let()= textFileConvertLines(simulationFile_mix(simCode,&mixheader), '<%modelNamePrefix%>_11mix.c')
  let()= textFile(&mixheader, '<%modelNamePrefix%>_11mix.h')
  ""
end simulationFile_mixAndHeader;

template simulationFile_syn(SimCode simCode)
"Synchonous features"
::= match simCode
    case simCode as SIMCODE(__) then
      <<
      /* Synchronous systems */
      <%simulationFileHeader(simCode.fileNamePrefix)%>
      #if defined(__cplusplus)
      extern "C" {
      #endif

      <%functionInitSynchronous(clockedPartitions, modelNamePrefix(simCode))%>

      <%functionUpdateSynchronous(clockedPartitions, modelNamePrefix(simCode))%>

      <%functionSystemsSynchronous(clockedPartitions, modelNamePrefix(simCode))%>

      <%functionSavePreSynchronous(getSubPartitions(clockedPartitions), modelNamePrefix(simCode))%>

      #if defined(__cplusplus)
      }
      #endif
      <%\n%>
      >>
  end match
end simulationFile_syn;

template functionSavePreSynchronous(list<SimCode.SubPartition> subPartitions, String modelNamePrefix)
::=
  let preVars = subPartitions |> subPartition =>
    functionSavePreSynchronous1(subPartition); separator="\n"
  <<
  /* %v% = pre(%v%)*/
  void <%symbolName(modelNamePrefix,"function_savePreSynchronous")%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH

    <%preVars%>

    TRACE_POP
  }
  >>
end functionSavePreSynchronous;

template functionSavePreSynchronous1(SimCode.SubPartition subPartition)
::=
match subPartition
  case SUBPARTITION(__) then functionSavePreSynchronous2(vars)
end functionSavePreSynchronous1;

template functionSavePreSynchronous2(list<tuple<SimCodeVar.SimVar, Boolean>> vars)
::=
  vars |> var => functionSavePreSynchronous3(var); separator = "\n"
end functionSavePreSynchronous2;

template functionSavePreSynchronous3(tuple<SimCodeVar.SimVar, Boolean> var)
::=
let &sub = buffer ""
match var
  case (simVar, previous) then
    match simVar
      case SIMVAR(arrayCref=SOME(c), aliasvar=NOALIAS()) then
        '<%cref(c, &sub)%> = <%crefPre(c)%>;'
      case SIMVAR(aliasvar=NOALIAS()) then
        '<%cref(name, &sub)%> = <%crefPre(name)%>;'
end functionSavePreSynchronous3;

template isEventClock(DAE.ClockKind clock)
::=
match clock
  case EVENT_CLOCK(__) then boolStrC(true)
  else boolStrC(false)
end isEventClock;

template functionInitSynchronous(list<ClockedPartition> clockedPartitions, String modelNamePrefix)
"Synchonous features"
::=
  let body = clockedPartitions |> partition hasindex baseClockIdx =>

    let &varDecls = buffer ""
    let &auxFunction = buffer ""
    match partition
      case CLOCKED_PARTITION(__) then
        let baseClockStr = baseClockInit(baseClock, baseClockIdx, subPartitions, varDecls, auxFunction)
        <<
        <%varDecls%>
        <%auxFunction%>
        <%baseClockStr%>
        >>
  <<
  /* Initializes the clocks of model. */
  void <%symbolName(modelNamePrefix,"function_initSynchronous")%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH
    assertStreamPrint(threadData, data->modelData->nBaseClocks==<%listLength(clockedPartitions)%>, "Number of base clocks doesn't match number of clocks that are initialized! Code generation error!");
    data->simulationInfo->baseClocks = calloc(<%listLength(clockedPartitions)%>, sizeof(BASECLOCK_DATA));

    <%body%>
    TRACE_POP
  }
  >>
end functionInitSynchronous;

template baseClockInit(ClockKind baseClock, Integer baseClockIdx, list<SubPartition> subPartitions, Text &varDecls, Text &auxFunction)
::=
  let &preExp = buffer ""
  let intervalCounter = match baseClock
    case RATIONAL_CLOCK() then
      if isConst(intervalCounter) then
        daeExp(intervalCounter, contextOther, &preExp, &varDecls, &auxFunction)
      else
        '-1 /* Interval set in _updateSynchronous */'
    case INFERRED_CLOCK() then
      '1'
    else
      '-1'
  let resolution = match baseClock
    case RATIONAL_CLOCK() then
      daeExp(resolution, contextOther, &preExp, &varDecls, &auxFunction)
    else
      '1'
  let startInterval = match baseClock
    case EVENT_CLOCK() then
      daeExp(startInterval, contextOther, &preExp, &varDecls, &auxFunction)
    else
      '0'
  let interval = match baseClock
    case REAL_CLOCK() then
      if isConst(interval) then
        daeExp(interval, contextOther, &preExp, &varDecls, &auxFunction)
      else
        '-1 /* Interval set in _updateSynchronous */'
    case INFERRED_CLOCK() then
      '1'
    else
      '-1'
  let computeInterval = match baseClock
    case RATIONAL_CLOCK() then
      if isConst(intervalCounter) then
        <<
        data->simulationInfo->baseClocks[<%baseClockIdx%>].interval = DIVISION((modelica_real)data->simulationInfo->baseClocks[<%baseClockIdx%>].intervalCounter, (modelica_real)data->simulationInfo->baseClocks[<%baseClockIdx%>].resolution, "base-clock[<%baseClockIdx%>].interval = intervalCounter/resolution");
        >>
      else
        ''
  let subClocksInfo = subPartitions |> subPartition hasindex subClockIdx =>
    subPartitionStr(subPartition, baseClockIdx, subClockIdx); separator="\n"
  let warning = match baseClock
    case INFERRED_CLOCK() then
      <<
      warningStreamPrint(LOG_STDOUT, 0, "Inferred clock, using default clock \'Clock(intervalCounter=1, resolution=1)\'");
      >>
    else ''
  <<
  /* Base-Clock <%baseClockIdx%> */
  <%warning%>
  data->simulationInfo->baseClocks[<%baseClockIdx%>] = (BASECLOCK_DATA){
    .resolution = <%resolution%>,
    .intervalCounter = <%intervalCounter%>,
    .interval = <%interval%>,
    .nSubClocks = <%listLength(subPartitions)%>,
    .isEventClock = <%isEventClock(baseClock)%>,
    .stats = (CLOCK_STATS){<%startInterval%>, 0, -1}};
  <%computeInterval%>
  data->simulationInfo->baseClocks[<%baseClockIdx%>].subClocks = calloc(<%listLength(subPartitions)%>, sizeof(SUBCLOCK_DATA));
  <%subClocksInfo%>

  >>
end baseClockInit;

template subPartitionStr(SubPartition subPartition, Integer baseClockIdx, Integer subClockIdx)
::=
match subPartition
  case SUBPARTITION(subClock = SUBCLOCK(__), holdEvents=holdEvents) then
    let methodStr = match subClock.solver
      case NONE() then ""
      else "External"
    <<
    data->simulationInfo->baseClocks[<%baseClockIdx%>].subClocks[<%subClockIdx%>] = (SUBCLOCK_DATA) {
      .shift = <%makeCRational(subClock.shift)%>,
      .factor = <%makeCRational(subClock.factor)%>,
      .solverMethod = "<%methodStr%>",
      .holdEvents = <%boolStrC(holdEvents)%>,
      .stats = (CLOCK_STATS) {0, 0, -1}};
    >>
end subPartitionStr;

template makeCRational(Rational rational)
::=
match rational
  case RATIONAL(__) then
    <<
    makeRATIONAL(<%nom%>, <%denom%>)
    >>
end makeCRational;

template functionUpdateSynchronous(list<ClockedPartition> clockedPartitions, String modelNamePrefix)
::=
  let &varDecls = buffer ""
  let &auxFunction = buffer ""
  let body = clockedPartitions |> partition hasindex i =>
    match partition
      case CLOCKED_PARTITION(__) then
        let caseBody = updatePartition(i, baseClock, &varDecls, &auxFunction)
        <<
        case <%i%>:
          <%caseBody%>
          break;
        >>; separator = "\n"
  <<
  <%auxFunction%>
  /* Update base-clock. */
  void <%symbolName(modelNamePrefix,"function_updateSynchronous")%>(DATA *data, threadData_t *threadData, long base_idx)
  {
    TRACE_PUSH
    <%varDecls%>
    modelica_boolean ret;
    switch (base_idx) {
      <%body%>
      default:
        throwStreamPrint(NULL, "Internal Error: unknown base partition %ld", base_idx);
        break;
    }
    TRACE_POP
  }
  >>
end functionUpdateSynchronous;

template updatePartition(Integer i, DAE.ClockKind baseClock, Text &varDecls, Text &auxFunction)
"Update intervalCounter or interval of base-clock"
::=
  let &preExp = buffer ""

  match baseClock
    case RATIONAL_CLOCK() then
      if isConst(intervalCounter) then
        <<
        /* Nothing to do */
        >>
      else
        let intervalCounterStr = daeExp(intervalCounter, contextOther, &preExp, &varDecls, &auxFunction)
        <<
        <%preExp%>
        data->simulationInfo->baseClocks[base_idx].intervalCounter = <%intervalCounterStr%>;
        data->simulationInfo->baseClocks[base_idx].interval = DIVISION((modelica_real)data->simulationInfo->baseClocks[base_idx].intervalCounter, (modelica_real)data->simulationInfo->baseClocks[base_idx].resolution, "intervalCounter/resolution");
        >>
    case REAL_CLOCK() then
      if isConst(interval) then
        <<
        /* Nothing to do */
        >>
      else
        let interval_ = daeExp(interval, contextOther, &preExp, &varDecls, &auxFunction)
        <<
        <%preExp%>
        data->simulationInfo->baseClocks[base_idx].interval = <%interval_%>;
        >>
    case INFERRED_CLOCK()
    case SOLVER_CLOCK()
    case EVENT_CLOCK() then
      <<
      /* Nothing to do */
      >>
    else 'ERROR in updatePartition'
end updatePartition;


template functionSystemsSynchronousSubClocks(list<SubPartition> subPartitions, Integer base_idx, String modelNamePrefix)
::=
  let subCases = subPartitions |> subPartition hasindex sub_idx =>
    match subPartition
      case SUBPARTITION(__) then
        let name = 'functionEquationsSynchronous_system_<%base_idx%>_<%sub_idx%>'
        <<
        case <%sub_idx%>:
          ret = <%symbolName(modelNamePrefix, name)%>(data, threadData);
          break;
        >>
      else ""
    ; separator = "\n"

  <<
  case <%base_idx%>:
    switch (sub_idx) {
      <%subCases%>
      default:
        throwStreamPrint(NULL, "Internal Error: unknown sub-clock partition %ld", sub_idx);
        ret = 1;
        break;
    }
    break;
  >>
end functionSystemsSynchronousSubClocks;


template functionSystemsSynchronous(list<ClockedPartition> clockedPartitions, String modelNamePrefix)
::=
  let baseCases = clockedPartitions |> partition hasindex base_idx =>
    match partition
      case CLOCKED_PARTITION(__) then
        functionSystemsSynchronousSubClocks(subPartitions, base_idx, modelNamePrefix)
      else ""
    ; separator = "\n"

  let systs = clockedPartitions |> partition hasindex base_idx =>
    match partition
      case CLOCKED_PARTITION(__) then
        let funcCall = subPartitions |> subPart hasindex sub_idx =>
          match subPart
            case SUBPARTITION(__) then
            functionEquationsSynchronous(base_idx, sub_idx, vars, listAppend(equations, removedEquations), modelNamePrefix)
            else ""
        ; separator = "\n"
        <<
        <%funcCall%>
        >>
      else ""
    ; separator = "\n"

  <<

  <%systs%>

  /* Clocked systems equations */
  int <%symbolName(modelNamePrefix,"function_equationsSynchronous")%>(DATA *data, threadData_t *threadData, long base_idx, long sub_idx)
  {
    TRACE_PUSH
    int ret;

    switch (base_idx) {
      <%baseCases%>
      default:
        throwStreamPrint(NULL, "Internal Error: unknown base-clock partition %ld", base_idx);
        ret = 1;
        break;
    }

    TRACE_POP
    return ret;
  }
  >>

end functionSystemsSynchronous;

template functionEquationsSynchronous(Integer base_idx, Integer sub_idx, list<tuple<SimCodeVar.SimVar, Boolean>> vars, list<SimEqSystem> equations, String modelNamePrefix)
::=
  <<
  <%equations |> eq => equation_impl(base_idx, sub_idx, eq, contextOther, modelNamePrefix, false) ; separator="\n"%>

  int <%symbolName(modelNamePrefix, 'functionEquationsSynchronous_system_<%base_idx%>_<%sub_idx%>')%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH
    int i;

    <%addRootsTempArray()%>

    <%equations |> eq => equation_call(eq, modelNamePrefix) ; separator="\n"%>

    TRACE_POP
    return 0;
  }
  >>
end functionEquationsSynchronous;

template simulationFile_exo(SimCode simCode)
"External Objects"
::=
  match simCode
    case simCode as SIMCODE(__) then
    <<
    /* External objects file */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #if defined(__cplusplus)
    extern "C" {
    #endif

    <%functionCallExternalObjectDestructors(extObjInfo, modelNamePrefix(simCode))%>
    #if defined(__cplusplus)
    }
    #endif
    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_exo;

template simulationFile_nls(SimCode simCode)
"Non Linear Systems"
::=
  match simCode
    case simCode as SIMCODE(modelInfo=MODELINFO(varInfo=varInfo as VARINFO(__),nonLinearSystems=nonLinearSystems)) then
    let modelNamePrefixStr = modelNamePrefix(simCode)
    <<
    /* Non Linear Systems */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #include "<%simCode.fileNamePrefix%>_12jac.h"
    #include "simulation/jacobian_util.h"
    #if defined(__cplusplus)
    extern "C" {
    #endif
    <%functionNonLinearResidualsMultiFile(nonLinearSystems, Flags.getConfigInt(Flags.EQUATIONS_PER_FILE), simCode.fullPathPrefix, simCode.fileNamePrefix, "02nls", modelNamePrefixStr)%>

    <%if intGt(varInfo.numNonLinearSystems, 0) then functionInitialNonLinearSystems(nonLinearSystems, modelNamePrefixStr)%>

    #if defined(__cplusplus)
    }
    #endif
    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_nls;

template simulationFile_lsy(SimCode simCode)
"Linear Systems"
::=
  match simCode
    case simCode as SIMCODE(modelInfo=MODELINFO(varInfo=varInfo as VARINFO(__),linearSystems=linearSystems)) then
    <<
    /* Linear Systems */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #include "<%simCode.fileNamePrefix%>_12jac.h"
    #if defined(__cplusplus)
    extern "C" {
    #endif

    <%functionSetupLinearSystems(linearSystems, modelNamePrefix(simCode))%>

    <% if intGt(varInfo.numLinearSystems,0) then functionInitialLinearSystems(linearSystems, modelNamePrefix(simCode))%>

    #if defined(__cplusplus)
    }
    #endif
    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_lsy;

template simulationFile_set(SimCode simCode)
"Initial State Set"
::=
  match simCode
    case simCode as SIMCODE(__) then
    <<
    /* Initial State Set */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #include "<%simCode.fileNamePrefix%>_11mix.h"
    #include "<%simCode.fileNamePrefix%>_12jac.h"
    #if defined(__cplusplus)
    extern "C" {
    #endif
    <%functionInitialStateSets(simCode, stateSets, modelNamePrefix(simCode))%>

    #if defined(__cplusplus)
    }
    #endif
    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_set;

template simulationFile_evt(SimCode simCode)
"Events: Sample, Zero Crossings, Relations, Discrete Changes"
::=
  match simCode
    case simCode as SIMCODE(__) then
    <<
    /* Events: Sample, Zero Crossings, Relations, Discrete Changes */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #if defined(__cplusplus)
    extern "C" {
    #endif

    <%functionInitSample(timeEvents, modelNamePrefix(simCode))%>

    <%functionZeroCrossing(zeroCrossings, equationsForZeroCrossings, modelNamePrefix(simCode))%>

    <%functionRelations(relations, modelNamePrefix(simCode))%>

    #if defined(__cplusplus)
    }
    #endif
    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_evt;

template simulationFile_inz(SimCode simCode)
"Initialization"
::=
  match simCode
    case simCode as SIMCODE(modelInfo=MODELINFO(varInfo=varInfo as VARINFO(__))) then
    <<
    /* Initialization */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #include "<%simCode.fileNamePrefix%>_11mix.h"
    #include "<%simCode.fileNamePrefix%>_12jac.h"
    #if defined(__cplusplus)
    extern "C" {
    #endif

    <%functionInitialEquations(initialEquations, listLength(initialEquations), simCode.fileNamePrefix, simCode.fullPathPrefix, modelNamePrefix(simCode),
      /* initial: only to be treated as first system if there is no lambda_0 system */ intEq(listLength(initialEquations_lambda0), 0))%>
    <%functionInitialEquations_lambda0(initialEquations_lambda0, modelNamePrefix(simCode))%>
    <%functionRemovedInitialEquations(removedInitialEquations, modelNamePrefix(simCode))%>

    <%if intGt(varInfo.numMixedSystems,0) then functionInitialMixedSystems(initialEquations, initialEquations_lambda0, parameterEquations, allEquations, jacobianMatrices, modelNamePrefix(simCode))%>

    #if defined(__cplusplus)
    }
    #endif
    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_inz;

template simulationFile_dly(SimCode simCode)
"Delay"
::=
  match simCode
    case simCode as SIMCODE(__) then
    <<
    /* Delay */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #if defined(__cplusplus)
    extern "C" {
    #endif

    <%functionStoreDelayed(delayedExps, modelNamePrefix(simCode))%>

    #if defined(__cplusplus)
    }
    #endif
    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_dly;

template simulationFile_spd(SimCode simCode)
"SpatialDistribution"
::=
  match simCode
    case simCode as SIMCODE(__) then
    <<
    /* spatialDistribution */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #if defined(__cplusplus)
    extern "C" {
    #endif

    <%functionStoreSpatialDistribution(spatialInfo, modelNamePrefix(simCode))%>

    <%functionInitSpatialDistribution(spatialInfo, modelNamePrefix(simCode))%>

    #if defined(__cplusplus)
    }
    #endif
    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_spd;

template simulationFile_bnd(SimCode simCode)
"update bound parameters and variable attributes (start, nominal, min, max)"
::=
  match simCode
    case simCode as SIMCODE(__) then
    <<
    /* update bound parameters and variable attributes (start, nominal, min, max) */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #if defined(__cplusplus)
    extern "C" {
    #endif

    <%functionUpdateBoundVariableAttributes(simCode, startValueEquations, nominalValueEquations, minValueEquations, maxValueEquations, modelNamePrefix(simCode))%>

    <%functionUpdateBoundParameters(selectScalarLiteralAssignments(parameterEquations), filterScalarLiteralAssignments(parameterEquations), simCode.fileNamePrefix, simCode.fullPathPrefix, modelNamePrefix(simCode), simCode)%>

    #if defined(__cplusplus)
    }
    #endif
    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_bnd;

template simulationFile_alg(SimCode simCode)
"Algebraic"
::=
  match simCode
    case simCode as SIMCODE(__) then
    <<
    /* Algebraic */
    <%simulationFileHeader(simCode.fileNamePrefix)%>

    #ifdef __cplusplus
    extern "C" {
    #endif

    <%functionAlgebraic(algebraicEquations, modelNamePrefix(simCode))%>

    #ifdef __cplusplus
    }
    #endif<%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_alg;

template simulationFile_asr(SimCode simCode)
"Asserts"
::=
  match simCode
    case simCode as SIMCODE(__) then
    <<
    /* Asserts */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #if defined(__cplusplus)
    extern "C" {
    #endif

    <%functionAssertsforCheck(algorithmAndEquationAsserts, modelNamePrefix(simCode))%>

    #if defined(__cplusplus)
    }
    #endif
    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_asr;

template simulationFile_mix(SimCode simCode, Text &header)
"Mixed Systems"
::=
  match simCode
    case simCode as SIMCODE(__) then
    let modelNamePrefixStr = modelNamePrefix(simCode)
    <<
    /* Mixed Systems */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #include "<%simCode.fileNamePrefix%>_11mix.h"
    <%functionSetupMixedSystems(initialEquations, initialEquations_lambda0, parameterEquations, allEquations, jacobianMatrices, &header, modelNamePrefixStr)%>

    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_mix;

template simulationFile_jac(SimCode simCode)
"Jacobians"
::=
  match simCode
    case simCode as SIMCODE(__) then
    <<
    /* Jacobians <%listLength(jacobianMatrices)%> */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #include "<%fileNamePrefix%>_12jac.h"
    #include "simulation/jacobian_util.h"
    #include "util/omc_file.h"
    <%functionAnalyticJacobians(jacobianMatrices, modelNamePrefix(simCode), simCode.fileNamePrefix)%>

    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_jac;

template simulationFile_jac_header(SimCode simCode)
"Jacobians"
::=
  match simCode
    case simCode as SIMCODE(__) then
    <<
    /* Jacobians */
    static const REAL_ATTRIBUTE dummyREAL_ATTRIBUTE = omc_dummyRealAttribute;

    <%symJacDefinition(jacobianMatrices, modelNamePrefix(simCode))%>
    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_jac_header;

template simulationFile_opt(SimCode simCode)
"Optimization"
::=
  match simCode
    case simCode as SIMCODE(__) then
    let modelNamePrefixStr = modelNamePrefix(simCode)
    <<
    /* Optimization */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #include "<%fileNamePrefix%>_12jac.h"
    #if defined(__cplusplus)
    extern "C" {
    #endif
    <%optimizationComponents(classAttributes, simCode, modelNamePrefixStr)%>
    #if defined(__cplusplus)
    }
    #endif
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_opt;

template simulationFile_opt_header(SimCode simCode)
"Jacobians"
::=
  match simCode
    case simCode as SIMCODE(__) then
    let modelNamePrefixStr = modelNamePrefix(simCode)
    <<
    #if defined(__cplusplus)
      extern "C" {
    #endif
      int <%symbolName(modelNamePrefixStr,"mayer")%>(DATA* data, modelica_real** res, short*);
      int <%symbolName(modelNamePrefixStr,"lagrange")%>(DATA* data, modelica_real** res, short *, short *);
      int <%symbolName(modelNamePrefixStr,"pickUpBoundsForInputsInOptimization")%>(DATA* data, modelica_real* min, modelica_real* max, modelica_real*nominal, modelica_boolean *useNominal, char ** name, modelica_real * start, modelica_real * startTimeOpt);
      int <%symbolName(modelNamePrefixStr,"setInputData")%>(DATA *data, const modelica_boolean file);
      int <%symbolName(modelNamePrefixStr,"getTimeGrid")%>(DATA *data, modelica_integer * nsi, modelica_real**t);
    #if defined(__cplusplus)
    }
    #endif
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_opt_header;

template simulationFile_lnz(SimCode simCode)
"Linearization"
::=
  match simCode
    case simCode as SIMCODE(__) then
    <<
    /* Linearization */
    <%simulationFileHeader(simCode.fileNamePrefix)%>
    #if defined(__cplusplus)
    extern "C" {
    #endif
    <%
    if stringEq(Flags.getConfigString(LINEARIZATION_DUMP_LANGUAGE),"modelica")
      then functionlinearmodel(modelInfo, modelNamePrefix(simCode))
    else if stringEq(Flags.getConfigString(LINEARIZATION_DUMP_LANGUAGE),"matlab")
      then functionlinearmodelMatlab(modelInfo, modelNamePrefix(simCode))
    else if stringEq(Flags.getConfigString(LINEARIZATION_DUMP_LANGUAGE),"julia")
      then functionlinearmodelJulia(modelInfo, modelNamePrefix(simCode))
    else if stringEq(Flags.getConfigString(LINEARIZATION_DUMP_LANGUAGE),"python")
      then functionlinearmodelPython(modelInfo, modelNamePrefix(simCode))
    %>
    #if defined(__cplusplus)
    }
    #endif
    <%\n%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
  end match
end simulationFile_lnz;

template defineSimVarArray(SimVar simVar, String arrayName)
  "Generates a define statement for a parameter."
::=
let &sub = buffer ""
 match simVar
  case SIMVAR(arrayCref=SOME(c),aliasvar=NOALIAS()) then
    <<
    /* <%crefStrNoUnderscore(c)%> */
    // #define <%cref(c, &sub)%> data->simulationInfo->daeModeData-><%arrayName%>[<%index%>]

    /* <%crefStrNoUnderscore(name)%> */
    // #define <%cref(name, &sub)%> data->simulationInfo->daeModeData-><%arrayName%>[<%index%>]

    >>
  case SIMVAR(aliasvar=NOALIAS()) then
    <<
    /* <%crefStrNoUnderscore(name)%> */
    // #define <%cref(name, &sub)%> data->simulationInfo->daeModeData-><%arrayName%>[<%index%>]

    >>
  end match
end defineSimVarArray;

// TODO: This is probably not relevant anymore can be removed. We access residual and auxialry
// variables of daemode using cref2simvar now. No need to define them.
template simulationFile_dae_header(SimCode simCode)
"DAEmode header generation"
::=
  match simCode
    case simCode as SIMCODE(daeModeData=SOME(DAEMODEDATA(residualVars=residualVars,auxiliaryVars=auxiliaryVars))) then
    <<
    /* residual variable define for daeMode */
    <%residualVars |> var =>
      defineSimVarArray(var, "residualVars")
    ;separator="\n"%>
    /* auxiliary variable define for daeMode */
    <%auxiliaryVars |> var =>
      defineSimVarArray(var, "auxiliaryVars")
    ;separator="\n"%>
    >>
    /* adrpo: leave a newline at the end of file to get rid of the warning */
    case simCode as SIMCODE(__) then
    <<
    #ifndef <%fileNamePrefix%>_16DAE_H
    #define <%fileNamePrefix%>_16DAE_H
    #endif
    <%\n%>
    >>
  end match
end simulationFile_dae_header;

template simulationFile_dae(SimCode simCode)
"DAEmode equations generation"
::=
  match simCode
    case SIMCODE(modelInfo=MODELINFO(vars=SIMVARS(__)),
        daeModeData=SOME(DAEMODEDATA(daeEquations=daeEquations, sparsityPattern=sparsityPattern,
                                     algebraicVars=algebraicVars, residualVars=residualVars,
                                     auxiliaryVars=auxiliaryVars))) then
     let modelNamePrefixStr = modelNamePrefix(simCode)
     let initDAEmode =
       match sparsityPattern
       case SOME(JAC_MATRIX(sparsity=sparse, coloredCols=colorList, maxColorCols=maxColor)) then
         '<%initializeDAEmodeData(listLength(residualVars), algebraicVars, listLength(auxiliaryVars), sparse, colorList, maxColor, modelNamePrefixStr)%>'
       case NONE() then
         'int <%symbolName(modelNamePrefixStr,"initializeDAEmodeData")%>(DATA* data, DAEMODE_DATA* daeModeData){ return -1; }'
       end match
     <<
     /* DAE residuals */
     <%simulationFileHeader(fileNamePrefix)%>
     #include "simulation/solver/dae_mode.h"

     #ifdef __cplusplus
     extern "C" {
     #endif

     <%evaluateDAEResiduals(daeEquations, fileNamePrefix, fullPathPrefix, modelNamePrefixStr)%>

     <%initDAEmode%>

     #ifdef __cplusplus
     }
     #endif<%\n%>
     >>
     /* adrpo: leave a newline at the end of file to get rid of the warning */
    else
    let modelNamePrefixStr = modelNamePrefix(simCode)
    <<
    /* DAE residuals is empty */
     <%simulationFileHeader(fileNamePrefix(simCode))%>
    #ifdef __cplusplus
    extern "C" {
    #endif
    int <%symbolName(modelNamePrefixStr,"initializeDAEmodeData")%>(DATA* data, DAEMODE_DATA* daeModeData){ return -1; }
    #ifdef __cplusplus
    }
    #endif<%\n%>
    >>
  end match
end simulationFile_dae;

template simulationFile_inl(SimCode simCode)
"DAEmode equations generation"
::=
  match simCode
    case SIMCODE(modelInfo=MODELINFO(vars=SIMVARS(__)),inlineEquations={}) then
      let modelNamePrefixStr = modelNamePrefix(simCode)
      <<
      /* Inline equation file is empty */
      <%simulationFileHeader(fileNamePrefix(simCode))%>
      #ifdef __cplusplus
      extern "C" {
      #endif
      int <%symbolName(modelNamePrefixStr,"symbolicInlineSystem")%>(DATA *data, threadData_t *threadData){
      <% if intEq(Flags.getConfigEnum(Flags.SYM_SOLVER),0) then
      <<
        return -1;
      >>
      %>
      <% if intGt(Flags.getConfigEnum(Flags.SYM_SOLVER),0) then
      <<
        return 0;
      >>
      %>
      }
      #ifdef __cplusplus
      }
      #endif<%\n%>
      >>
    case SIMCODE(modelInfo=MODELINFO(vars=SIMVARS(__)),inlineEquations=inlineEquations) then
      let modelNamePrefixStr = modelNamePrefix(simCode)

      let funcNames = (inlineEquations |> eq => equationNames_(eq,contextSimulationNonDiscrete,modelNamePrefixStr))
      <<
      /* Inline equation file */
      <%simulationFileHeader(fileNamePrefix(simCode))%>

      #ifdef __cplusplus
      extern "C" {
      #endif

      <%(inlineEquations |> eq hasindex i0 =>
          equation_impl(-1, -1, eq, contextSimulationNonDiscrete, modelNamePrefixStr, false)
          ;separator="\n")%>

      /* inline equations*/
      int <%symbolName(modelNamePrefixStr,"symbolicInlineSystem")%>(DATA *data, threadData_t *threadData){

        TRACE_PUSH

        <%funcNames%>

        TRACE_POP
        return 0;
      }

      #ifdef __cplusplus
      }
      #endif<%\n%>
      >>
end simulationFile_inl;

template simulationFile(SimCode simCode, String guid, String isModelExchangeFMU)
  "Generates code for main C file for simulation target."
::=
  match simCode
    case simCode as SIMCODE(modelInfo=MODELINFO(varInfo=varInfo as VARINFO(__)), hpcomData=HPCOMDATA(__)) then
    let modelNamePrefixStr = modelNamePrefix(simCode)
    let mainInit = if boolOr(boolNot(stringEq("",isModelExchangeFMU)), Flags.isSet(HPCOM)) then
                     <<
                     mmc_init_nogc();
                     omc_alloc_interface = omc_alloc_interface_pooled;
                     omc_alloc_interface.init();
                     >>
                   else if stringEq(Config.simCodeTarget(),"JavaScript") then
                     <<
                     mmc_init_nogc();
                     omc_alloc_interface = omc_alloc_interface_pooled;
                     omc_alloc_interface.init();
                     >>
                   else
                     <<
                     MMC_INIT(0);
                     omc_alloc_interface.init();
                     >>
    let pminit = if Flags.getConfigBool(Flags.PARMODAUTO) then
                    <<
                    int num_threads = 0;
                    if(omc_flag[FLAG_PARMODNUMTHREADS]) {
                      num_threads = atoi(omc_flagValue[FLAG_PARMODNUMTHREADS]);
                    }
                    pm_model = PM_Model_create("<%fileNamePrefix%>", &data, threadData, num_threads);
                    PM_Model_load_ODE_system(pm_model, functionODE_systems);

                    >>
                 else ''
    let mainBody =
      <<
      <%symbolName(modelNamePrefixStr,"setupDataStruc")%>(&data, threadData);
      res = _main_initRuntimeAndSimulation(argc, newargv, &data, threadData);
      if(res == 0) {
        <%pminit%>
        res = _main_SimulationRuntime(argc, newargv, &data, threadData);
      }
      >>
    <<

    <%functionDAE(allEquations, modelNamePrefixStr)%>


    <%functionInitializeDataStruc(modelInfo, fileNamePrefix, guid, delayedExps, modelNamePrefixStr, isModelExchangeFMU)%>

    endflag
    >>
    /* adrpo: leave a newline at the end of file to get ridsymbolName(String fileNamePrefix of the warning */
  end match
end simulationFile;

template simulationFileHeader(String fileNamePrefix)
  "Generates header part of simulation file."
::=
    let daeHeader = if Flags.getConfigBool(Flags.DAE_MODE) then '#include "<%fileNamePrefix%>_16dae.h"'
    <<
    #include "<%fileNamePrefix%>_model.h"
    <%daeHeader%>
    >>
end simulationFileHeader;

template populateModelInfo(ModelInfo modelInfo, String fileNamePrefix, String guid, DelayedExpression delayed, String isModelExchangeFMU)
  "Generates information for data.modelInfo struct."
::=
  match modelInfo
  case MODELINFO(varInfo=VARINFO(__),vars=SIMVARS(__)) then
    <<
    OpenModelica_updateUriMapping(threadData, MMC_REFSTRUCTLIT(_OMC_LIT_RESOURCES));
    data->modelData->modelName = "<%dotPath(name)%>";
    data->modelData->modelFilePrefix = "<%fileNamePrefix%>";
    data->modelData->resultFileName = NULL;
    data->modelData->modelDir = "<%directory%>";
    data->modelData->modelGUID = "{<%guid%>}";
    data->modelData->encrypted = <%SimCodeUtil.isMocFile(fileName)%>;
    <% match isModelExchangeFMU
    case "1.0" then
      <<
      data->modelData->initXMLData = NULL;
      data->modelData->modelDataXml.infoXMLData =
      #if defined(OMC_MINIMAL_METADATA)
        NULL;
      #else
        #include "<%fileNamePrefix%>_info.c"
        ;
      #endif
      data->modelData->modelDataXml.fileName = NULL;
      >>
    case "" then
      <<
      #if defined(OPENMODELICA_XML_FROM_FILE_AT_RUNTIME)
      data->modelData->initXMLData = NULL;
      data->modelData->modelDataXml.infoXMLData = NULL;
      #else
      #if defined(_MSC_VER) /* handle joke compilers */
      {
      /* for MSVC we encode a string like char x[] = {'a', 'b', 'c', '\0'} */
      /* because the string constant limit is 65535 bytes */
      static const char contents_init[] =
        #include "<%fileNamePrefix%>_init.c"
        ;
      static const char contents_info[] =
        #include "<%fileNamePrefix%>_info.c"
        ;
        data->modelData->initXMLData = contents_init;
        data->modelData->modelDataXml.infoXMLData = contents_info;
      }
      #else /* handle real compilers */
      data->modelData->initXMLData =
      #include "<%fileNamePrefix%>_init.c"
        ;
      data->modelData->modelDataXml.infoXMLData =
      #include "<%fileNamePrefix%>_info.c"
        ;
      #endif /* defined(_MSC_VER) */
      #endif /* defined(OPENMODELICA_XML_FROM_FILE_AT_RUNTIME) */
      data->modelData->modelDataXml.fileName = "<%fileNamePrefix%>_info.json";
      data->modelData->resourcesDir = NULL;
      >>
    else
      <<
      data->modelData->initXMLData = NULL;
      data->modelData->modelDataXml.infoXMLData = NULL;
      GC_asprintf(&data->modelData->modelDataXml.fileName, "%s/<%fileNamePrefix%>_info.json", data->modelData->resourcesDir);
      >>
    %>
    data->modelData->runTestsuite = <%if Testsuite.isRunning() then "1" else "0"%>;
    data->modelData->nStates = <%varInfo.numStateVars%>;
    data->modelData->nVariablesReal = <%nVariablesReal(varInfo)%>;
    data->modelData->nDiscreteReal = <%varInfo.numDiscreteReal%>;
    data->modelData->nVariablesInteger = <%varInfo.numIntAlgVars%>;
    data->modelData->nVariablesBoolean = <%varInfo.numBoolAlgVars%>;
    data->modelData->nVariablesString = <%varInfo.numStringAlgVars%>;
    data->modelData->nParametersReal = <%varInfo.numParams%>;
    data->modelData->nParametersInteger = <%varInfo.numIntParams%>;
    data->modelData->nParametersBoolean = <%varInfo.numBoolParams%>;
    data->modelData->nParametersString = <%varInfo.numStringParamVars%>;
    data->modelData->nInputVars = <%varInfo.numInVars%>;
    data->modelData->nOutputVars = <%varInfo.numOutVars%>;
    data->modelData->nAliasReal = <%varInfo.numAlgAliasVars%>;
    data->modelData->nAliasInteger = <%varInfo.numIntAliasVars%>;
    data->modelData->nAliasBoolean = <%varInfo.numBoolAliasVars%>;
    data->modelData->nAliasString = <%varInfo.numStringAliasVars%>;
    data->modelData->nZeroCrossings = <%varInfo.numZeroCrossings%>;
    data->modelData->nSamples = <%varInfo.numTimeEvents%>;
    data->modelData->nRelations = <%varInfo.numRelations%>;
    data->modelData->nMathEvents = <%varInfo.numMathEventFunctions%>;
    data->modelData->nExtObjs = <%varInfo.numExternalObjects%>;
    data->modelData->modelDataXml.modelInfoXmlLength = 0;
    data->modelData->modelDataXml.nFunctions = <%listLength(functions)%>;
    data->modelData->modelDataXml.nProfileBlocks = 0;
    data->modelData->modelDataXml.nEquations = <%varInfo.numEquations%>;
    data->modelData->nMixedSystems = <%varInfo.numMixedSystems%>;
    data->modelData->nLinearSystems = <%varInfo.numLinearSystems%>;
    data->modelData->nNonLinearSystems = <%varInfo.numNonLinearSystems%>;
    data->modelData->nStateSets = <%varInfo.numStateSets%>;
    data->modelData->nJacobians = <%varInfo.numJacobians%>;
    data->modelData->nOptimizeConstraints = <%varInfo.numOptimizeConstraints%>;
    data->modelData->nOptimizeFinalConstraints = <%varInfo.numOptimizeFinalConstraints%>;
    data->modelData->nDelayExpressions = <%match delayed case
     DELAYED_EXPRESSIONS(__) then maxDelayedIndex%>;
    data->modelData->nBaseClocks = <%nClocks%>;
    data->modelData->nSpatialDistributions = <%nSpatialDistributions%>;
    data->modelData->nSensitivityVars = <%listLength(vars.sensitivityVars)%>;
    data->modelData->nSensitivityParamVars = <%varInfo.numSensitivityParameters%>;
    data->modelData->nSetcVars = <%varInfo.numSetcVars%>;
    data->modelData->ndataReconVars = <%varInfo.numDataReconVars%>;
    data->modelData->nSetbVars = <%varInfo.numSetbVars%>;
    data->modelData->nRelatedBoundaryConditions = <%varInfo.numRelatedBoundaryConditions%>;
    data->modelData->linearizationDumpLanguage = <%
    if stringEq(Flags.getConfigString(LINEARIZATION_DUMP_LANGUAGE),"modelica") then 'OMC_LINEARIZE_DUMP_LANGUAGE_MODELICA'
    else if stringEq(Flags.getConfigString(LINEARIZATION_DUMP_LANGUAGE),"matlab") then 'OMC_LINEARIZE_DUMP_LANGUAGE_MATLAB'
    else if stringEq(Flags.getConfigString(LINEARIZATION_DUMP_LANGUAGE),"julia") then 'OMC_LINEARIZE_DUMP_LANGUAGE_JULIA'
    else if stringEq(Flags.getConfigString(LINEARIZATION_DUMP_LANGUAGE),"python") then 'OMC_LINEARIZE_DUMP_LANGUAGE_PYTHON'
    %>;
    >>
  end match
end populateModelInfo;

template functionInitializeDataStruc(ModelInfo modelInfo, String fileNamePrefix, String guid, DelayedExpression delayed, String modelNamePrefix, String isModelExchangeFMU)
  "Generates function in simulation file."
::=
  <<
 
  >>
end functionInitializeDataStruc;

template functionSimProfDef(SimEqSystem eq, Integer value, Text &reverseProf)
  "Generates function in simulation file."
::=
  match eq
  case SES_MIXED(__) then
    let &reverseProf += 'data->modelData->equationInfo_reverse_prof_index[<%value%>] = <%index%>;<%\n%>'
    <<
    #define SIM_PROF_EQ_<%index%> <%value%><%\n%>
    >>
  // no dynamic tearing
  case SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing=NONE()) then
    let &reverseProf += 'data->modelData->equationInfo_reverse_prof_index[<%value%>] = <%ls.index%>;<%\n%>'
    <<
    #define SIM_PROF_EQ_<%ls.index%> <%value%><%\n%>
    >>
  case SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__), alternativeTearing=NONE()) then
    let &reverseProf += 'data->modelData->equationInfo_reverse_prof_index[<%value%>] = <%nls.index%>;<%\n%>'
    <<
    #define SIM_PROF_EQ_<%nls.index%> <%value%><%\n%>
    >>
  // dynamic tearing
  case SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing = SOME(at as LINEARSYSTEM(__))) then
    let &reverseProf += 'data->modelData->equationInfo_reverse_prof_index[<%value%>] = <%ls.index%>;<%\n%>'
    let &reverseProf += 'data->modelData->equationInfo_reverse_prof_index[<%value%>] = <%at.index%>;<%\n%>'
    <<
    #define SIM_PROF_EQ_<%ls.index%> <%value%><%\n%>
    #define SIM_PROF_EQ_<%at.index%> <%value%><%\n%>
    >>
  case SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__), alternativeTearing = SOME(at as NONLINEARSYSTEM(__))) then
    let &reverseProf += 'data->modelData->equationInfo_reverse_prof_index[<%value%>] = <%nls.index%>;<%\n%>'
    let &reverseProf += 'data->modelData->equationInfo_reverse_prof_index[<%value%>] = <%at.index%>;<%\n%>'
    <<
    #define SIM_PROF_EQ_<%nls.index%> <%value%><%\n%>
    #define SIM_PROF_EQ_<%at.index%> <%value%><%\n%>
    >>
  end match
end functionSimProfDef;

template variableDefinitions(ModelInfo modelInfo, list<BackendDAE.TimeEvent> timeEvents)
  "Generates global data in simulation file."
::=
  if true then "" else
  let () = System.tmpTickReset(1000)
  match modelInfo
    case MODELINFO(varInfo=VARINFO(numStateVars=numStateVars, numAlgVars= numAlgVars, numDiscreteReal=numDiscreteReal, numOptimizeConstraints=numOptimizeConstraints, numOptimizeFinalConstraints=numOptimizeFinalConstraints), vars=SIMVARS(__)) then
      <<
      /* States */
      <%vars.stateVars |> var =>
        globalDataVarDefine(var, "realVars")
      ;separator="\n"%>

      /* StatesDerivatives */
      <%vars.derivativeVars |> var =>
        globalDataVarDefine(var, "realVars")
      ;separator="\n"%>

      /* Non Discrete Real Algebraic Vars */
      <%vars.algVars |> var =>
        globalDataVarDefine(var, "realVars")
      ;separator="\n"%>

      /* Discrete Real Algebraic Vars */
      <%vars.discreteAlgVars |> var =>
        globalDataVarDefine(var, "realVars")
      ;separator="\n"%>

      /* Nonlinear Constraints For Dyn. Optimization */
      <%vars.realOptimizeConstraintsVars |> var =>
        globalDataVarDefine(var, "realVars")
      ;separator="\n"%>

      /* Nonlinear Final Constraints For Dyn. Optimization */
      <%vars.realOptimizeFinalConstraintsVars |> var =>
        globalDataVarDefine(var, "realVars")
      ;separator="\n"%>

      /* Algebraic Parameter */
      <%vars.paramVars |> var =>
        globalDataParDefine(var, "realParameter")
      ;separator="\n"%>

      /* External Objects */
      <%vars.extObjVars |> var =>
        globalDataParDefine(var, "extObjs")
      ;separator="\n"%>

      /* Algebraic Integer Vars */
      <%vars.intAlgVars |> var =>
        globalDataVarDefine(var, "integerVars")
      ;separator="\n"%>

      /* Algebraic Integer Parameter */
      <%vars.intParamVars |> var =>
        globalDataParDefine(var, "integerParameter")
      ;separator="\n"%>

      /* Algebraic Boolean Vars */
      <%vars.boolAlgVars |> var =>
        globalDataVarDefine(var, "booleanVars")
      ;separator="\n"%>

      /* Algebraic Boolean Parameters */
      <%vars.boolParamVars |> var =>
        globalDataParDefine(var, "booleanParameter")
      ;separator="\n"%>

      /* Algebraic String Variables */
      <%vars.stringAlgVars |> var =>
        globalDataVarDefine(var, "stringVars")
      ;separator="\n"%>

      /* Algebraic String Parameter */
      <%vars.stringParamVars |> var =>
        globalDataParDefine(var, "stringParameter")
      ;separator="\n"%>

      >>
  end match
end variableDefinitions;

template globalDataParDefine(SimVar simVar, String arrayName)
  "Generates a define statement for a parameter."
::=
let &sub = buffer ""
 match simVar
  case SIMVAR(arrayCref=SOME(c),aliasvar=NOALIAS()) then
    <<
    /* <%crefStrNoUnderscore(c)%> */
    #define <%cref(c, &sub)%> data->simulationInfo-><%arrayName%>[<%index%>]

    /* <%crefStrNoUnderscore(name)%> */
    #define <%cref(name, &sub)%> data->simulationInfo-><%arrayName%>[<%index%>]
    #define _<%cref(name, &sub)%>(i) <%cref(name, &sub)%>

    >>
  case SIMVAR(aliasvar=NOALIAS()) then
    <<
    /* <%crefStrNoUnderscore(name)%> */
    #define <%cref(name, &sub)%> data->simulationInfo-><%arrayName%>[<%index%>]
    #define _<%cref(name, &sub)%>(i) <%cref(name, &sub)%>

    >>
  end match
end globalDataParDefine;

template globalDataVarDefine(SimVar simVar, String arrayName) "template globalDataVarDefine
  Generates a define statement for a varable in the global data section."
::=
let &sub = buffer ""
  match simVar
  case SIMVAR(arrayCref=SOME(c),aliasvar=NOALIAS()) then
    <<
    /* <%crefStrNoUnderscore(c)%> */
    #define _<%cref(c, &sub)%>(i) data->localData[i]-><%arrayName%>[<%index%>]
    #define <%cref(c, &sub)%> _<%cref(c, &sub)%>(0)
    #define <%cref(crefPrefixPre(c), &sub)%> data->simulationInfo-><%arrayName%>Pre[<%index%>]

    /* <%crefStrNoUnderscore(name)%> */
    #define _<%cref(name, &sub)%>(i) data->localData[i]-><%arrayName%>[<%index%>]
    #define <%cref(name, &sub)%> _<%cref(name, &sub)%>(0)
    #define <%cref(crefPrefixPre(name), &sub)%> data->simulationInfo-><%arrayName%>Pre[<%index%>]

    >>
  case SIMVAR(aliasvar=NOALIAS()) then
    <<
    /* <%crefStrNoUnderscore(name)%> */
    #define _<%cref(name, &sub)%>(i) data->localData[i]-><%arrayName%>[<%index%>]
    #define <%cref(name, &sub)%> _<%cref(name, &sub)%>(0)
    #define <%cref(crefPrefixPre(name), &sub)%> data->simulationInfo-><%arrayName%>Pre[<%index%>]
    #define _<%cref(crefPrefixPre(name), &sub)%>(i) <%cref(crefPrefixPre(name), &sub)%>

    >>
  end match
end globalDataVarDefine;

template globalDataAliasVarArray(String _type, String _name, list<SimVar> items)
  "Generates array with variable names in global data section."
::=
  match items
  case {} then
    <<
      <%_type%> <%_name%>[1] = {{0,0,-1}};
    >>
  case items then
    <<
      <%_type%> <%_name%>[<%listLength(items)%>] = {
        <%items |> var as SIMVAR(__) => '{<%aliasVarNameType(aliasvar)%>,<%index%>}'; separator=",\n"%>
      };
    >>
  end match
end globalDataAliasVarArray;

template symJacDefinition(list<JacobianMatrix> JacobianMatrices, String modelNamePrefix) "template variableDefinitionsJacobians
  Generates defines for jacobian vars."
::=
  let symbolicJacsDefine = (JacobianMatrices |> jac as JAC_MATRIX(columns=jacColumn, seedVars=seedVars, matrixName=name, jacobianIndex=indexJacobian)  =>
    <<
    #define <%symbolName(modelNamePrefix,"INDEX_JAC_")%><%name%> <%indexJacobian%>
    int <%symbolName(modelNamePrefix,"functionJac")%><%name%>_column(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *thisJacobian, ANALYTIC_JACOBIAN *parentJacobian);
    int <%symbolName(modelNamePrefix,"initialAnalyticJacobian")%><%name%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian);
    <%genericCallHeaders(jac.generic_loop_calls, createJacContext(jac.crefsHT))%>
    >>
    ;separator="\n\n";empty)

  <<
  #if defined(__cplusplus)
  extern "C" {
  #endif

  /* Jacobian Variables */
  <%symbolicJacsDefine%>

  #if defined(__cplusplus)
  }
  #endif
  >>
end symJacDefinition;

template aliasVarNameType(AliasVariable var)
  "Generates type of alias."
::=
let &sub = buffer ""
  match var
  case NOALIAS() then
    <<
    0,0
    >>
  case ALIAS(__) then
    <<
    &<%cref(varName, &sub)%>,0
    >>
  case NEGATEDALIAS(__) then
    <<
    &<%cref(varName, &sub)%>,1
    >>
  end match
end aliasVarNameType;

template functionCallExternalObjectDestructors(ExtObjInfo extObjInfo, String modelNamePrefix)
  "Generates function in simulation file."
::=
let &sub = buffer ""
  match extObjInfo
  case extObjInfo as EXTOBJINFO(__) then
    <<
    void <%symbolName(modelNamePrefix,"callExternalObjectDestructors")%>(DATA *data, threadData_t *threadData)
    {
      if(data->simulationInfo->extObjs)
      {
        <%listReverse(extObjInfo.vars) |> var as SIMVAR(varKind=ext as EXTOBJ(__)) => 'omc_<%underscorePath(ext.fullClassName)%>_destructor(threadData,<%cref(var.name, &sub)%>);' ;separator="\n"%>
        free(data->simulationInfo->extObjs);
        data->simulationInfo->extObjs = 0;
      }
    }
    >>
  end match
end functionCallExternalObjectDestructors;

template functionInput(SimCode simCode, ModelInfo modelInfo, String modelNamePrefix)
  "Generates function in simulation file."
::=
let &sub = buffer ""
  match modelInfo
  case MODELINFO(vars=SIMVARS(__)) then
    <<
    int <%symbolName(modelNamePrefix,"input_function")%>(DATA *data, threadData_t *threadData)
    {
      TRACE_PUSH

      <%vars.inputVars |> SIMVAR(name=name, type_=T_REAL()) hasindex i0 =>
        '<%cref(name, &sub)%> = data->simulationInfo->inputVars[<%i0%>];'
        ;separator="\n"
      %>

      TRACE_POP
      return 0;
    }

    int <%symbolName(modelNamePrefix,"input_function_init")%>(DATA *data, threadData_t *threadData)
    {
      TRACE_PUSH

      <%vars.inputVars |> SIMVAR(name=name, type_=T_REAL()) hasindex i0 =>
        match cref2simvar(name, simCode)
        case SIMVAR(aliasvar=NOALIAS()) then
        'data->simulationInfo->inputVars[<%i0%>] = data->modelData-><%expTypeShort(type_)%>VarsData[<%index%>].attribute.start;'
        else error(sourceInfo(), 'Cannot get attributes of alias variable <%crefStr(name)%>. Alias variables should have been replaced by the compiler before SimCode')
        ;separator="\n"
      %>

      TRACE_POP
      return 0;
    }

    int <%symbolName(modelNamePrefix,"input_function_updateStartValues")%>(DATA *data, threadData_t *threadData)
    {
      TRACE_PUSH

      <%vars.inputVars |> SIMVAR(name=name, type_=T_REAL()) hasindex i0 =>
        match cref2simvar(name, simCode)
        case SIMVAR(aliasvar=NOALIAS()) then
        'data->modelData-><%expTypeShort(type_)%>VarsData[<%index%>].attribute.start = data->simulationInfo->inputVars[<%i0%>];'
        else error(sourceInfo(), 'Cannot get attributes of alias variable <%crefStr(name)%>. Alias variables should have been replaced by the compiler before SimCode')
        ;separator="\n"
      %>

      TRACE_POP
      return 0;
    }

    int <%symbolName(modelNamePrefix,"inputNames")%>(DATA *data, char ** names){
      TRACE_PUSH

      <%vars.inputVars |> simVar as SIMVAR(__) hasindex i0 =>
        match cref2simvar(name, simCode)
        case SIMVAR(aliasvar=NOALIAS()) then
        'names[<%i0%>] = (char *) data->modelData-><%expTypeShort(type_)%>VarsData[<%index%>].info.name;'
        else error(sourceInfo(), 'Cannot get attributes of alias variable <%crefStr(name)%>. Alias variables should have been replaced by the compiler before SimCode')
        ;separator="\n"
      %>

      TRACE_POP
      return 0;
    }
    >>
  end match
end functionInput;

template functionDataInput(SimCode simCode, ModelInfo modelInfo, String modelNamePrefix)
  "Generates function in simulation file."
::=
let &sub = buffer ""
  match modelInfo
  case MODELINFO(vars=SIMVARS(__)) then
    <<
    int <%symbolName(modelNamePrefix,"data_function")%>(DATA *data, threadData_t *threadData)
    {
      TRACE_PUSH

      <%vars.dataReconinputVars |> SIMVAR(name=name, type_=T_REAL()) hasindex i0 =>
        '<%cref(name, &sub)%> = data->simulationInfo->datainputVars[<%i0%>];'
        ;separator="\n"
      %>
      TRACE_POP
      return 0;
    }

    int <%symbolName(modelNamePrefix,"dataReconciliationInputNames")%>(DATA *data, char ** names){
      TRACE_PUSH

      <%vars.dataReconinputVars |> simVar as SIMVAR(__) hasindex i0 =>
        match cref2simvar(name, simCode)
        case SIMVAR(aliasvar=NOALIAS()) then
        'names[<%i0%>] = (char *) data->modelData-><%expTypeShort(type_)%>VarsData[<%index%>].info.name;'
        else error(sourceInfo(), 'Cannot get attributes of alias variable <%crefStr(name)%>. Alias variables should have been replaced by the compiler before SimCode')
        ;separator="\n"
      %>

      TRACE_POP
      return 0;
    }

    int <%symbolName(modelNamePrefix,"dataReconciliationUnmeasuredVariables")%>(DATA *data, char ** names)
    {
      TRACE_PUSH

      <%vars.dataReconSetBVars |> simVar as SIMVAR(__) hasindex i0 =>
        match cref2simvar(name, simCode)
        case SIMVAR(aliasvar=NOALIAS()) then
        'names[<%i0%>] = (char *) data->modelData-><%expTypeShort(type_)%>VarsData[<%index%>].info.name;'
        else error(sourceInfo(), 'Cannot get attributes of alias variable <%crefStr(name)%>. Alias variables should have been replaced by the compiler before SimCode')
        ;separator="\n"
      %>

      TRACE_POP
      return 0;
    }
   >>
  end match
end functionDataInput;

template functionOutput(ModelInfo modelInfo, String modelNamePrefix)
  "Generates function in simulation file."
::=
let &sub = buffer ""
  match modelInfo
  case MODELINFO(vars=SIMVARS(__)) then
    <<
    int <%symbolName(modelNamePrefix,"output_function")%>(DATA *data, threadData_t *threadData)
    {
      TRACE_PUSH

      <%vars.outputVars |> SIMVAR(name=name, type_=T_REAL()) hasindex i0 =>
        'data->simulationInfo->outputVars[<%i0%>] = <%cref(name, &sub)%>;'
        ;separator="\n"
      %>

      TRACE_POP
      return 0;
    }
    >>
  end match
end functionOutput;


template functionSetC(ModelInfo modelInfo, String modelNamePrefix)
  "Generates function in simulation file."
::=
let &sub = buffer ""
  match modelInfo
  case MODELINFO(vars=SIMVARS(__)) then
    <<
    int <%symbolName(modelNamePrefix,"setc_function")%>(DATA *data, threadData_t *threadData)
    {
      TRACE_PUSH

      <%vars.dataReconSetcVars |> SIMVAR(name=name, type_=T_REAL()) hasindex i0 =>
        'data->simulationInfo->setcVars[<%i0%>] = <%cref(name, &sub)%>;'
        ;separator="\n"
      %>

      TRACE_POP
      return 0;
    }
    >>
  end match
end functionSetC;

template functionSetB(ModelInfo modelInfo, String modelNamePrefix)
  "Generates function in simulation file."
::=
let &sub = buffer ""
  match modelInfo
  case MODELINFO(vars=SIMVARS(__)) then
    <<
    int <%symbolName(modelNamePrefix,"setb_function")%>(DATA *data, threadData_t *threadData)
    {
      TRACE_PUSH

      <%vars.dataReconSetBVars |> SIMVAR(name=name, type_=T_REAL()) hasindex i0 =>
        'data->simulationInfo->setbVars[<%i0%>] = <%cref(name, &sub)%>;'
        ;separator="\n"
      %>

      TRACE_POP
      return 0;
    }
    >>
  end match
end functionSetB;

template functionInitSample(list<BackendDAE.TimeEvent> timeEvents, String modelNamePrefix)
  "Generates function initSample() in simulation file."
::=
  let &varDecls = buffer ""
  let &auxFunction = buffer ""
  let body = (timeEvents |> timeEvent =>
      match timeEvent
        case SAMPLE_TIME_EVENT(__) then
          let &preExp = buffer ""
          let e1 = daeExp(startExp, contextOther, &preExp, &varDecls, &auxFunction)
          let e2 = daeExp(intervalExp, contextOther, &preExp, &varDecls, &auxFunction)
          <<
          <%preExp%>
          /* sample <%index%> */
          data->modelData->samplesInfo[i].index = <%index%>;
          data->modelData->samplesInfo[i].start = <%e1%>;
          data->modelData->samplesInfo[i].interval = <%e2%> /* (max int for single time events) */;
          i++;
          >>
        else '')
  let res = <<
  /* Initializes the raw time events of the simulation using the now
     calcualted parameters. */
  void <%symbolName(modelNamePrefix,"function_initSample")%>(DATA *data, threadData_t *threadData)
  {
    long i=0;
    <%varDecls%>
    <%body%>
  }
  >>
  <<
  <%auxFunction%>
  <%res%>
  >>
end functionInitSample;


template functionInitialMixedSystems(list<SimEqSystem> initialEquations, list<SimEqSystem> initialEquations_lambda0, list<SimEqSystem> parameterEquations, list<SimEqSystem> allEquations, list<JacobianMatrix> jacobianMatrices, String modelNamePrefix)
  "Generates functions in simulation file."
::=
  let initbody = functionInitialMixedSystemsTemp(initialEquations)
  let initbody_lambda0 = functionInitialMixedSystemsTemp(initialEquations_lambda0)
  let parambody = functionInitialMixedSystemsTemp(parameterEquations)
  let body = functionInitialMixedSystemsTemp(allEquations)
  let jacobianbody = ((jacobianMatrices |> JAC_MATRIX(columns=clst) => (clst |> JAC_COLUMN(columnEqns=cEqns) => functionInitialMixedSystemsTemp(cEqns);separator="\n") ;separator="\n"))
  <<
  /* funtion initialize mixed systems */
  void <%symbolName(modelNamePrefix,"initialMixedSystem")%>(int nMixedSystems, MIXED_SYSTEM_DATA* mixedSystemData)
  {
    /* initial mixed systems */
    <%initbody%>
    /* initial_lambda0 mixed systems */
    <%initbody_lambda0%>
    /* parameter mixed systems */
    <%parambody%>
    /* model mixed systems */
    <%body%>
    /* jacobians mixed systems */
    <%jacobianbody%>
  }
  >>
end functionInitialMixedSystems;

template functionInitialMixedSystemsTemp(list<SimEqSystem> allEquations)
  "Generates functions in simulation file."
::=
  (allEquations |> eqn => (match eqn
     case eq as SES_MIXED(__) then
     let size = listLength(discVars)
     <<
     assertStreamPrint(NULL, nMixedSystems > <%indexMixedSystem%>, "Internal Error: nMixedSystems mismatch!");
     mixedSystemData[<%indexMixedSystem%>].equationIndex = <%index%>;
     mixedSystemData[<%indexMixedSystem%>].size = <%size%>;
     mixedSystemData[<%indexMixedSystem%>].solveContinuousPart = updateContinuousPart<%index%>;
     mixedSystemData[<%indexMixedSystem%>].updateIterationExps = updateIterationExpMixedSystem<%index%>;
     >>
   )
   ;separator="\n\n")
end functionInitialMixedSystemsTemp;


template functionSetupMixedSystems(list<SimEqSystem> initialEquations, list<SimEqSystem> initialEquations_lambda0, list<SimEqSystem> parameterEquations, list<SimEqSystem> allEquations, list<JacobianMatrix> jacobianMatrices, Text &header, String modelNamePrefixStr)
  "Generates functions in simulation file."
::=
  let initbody = functionSetupMixedSystemsTemp(initialEquations, &header,modelNamePrefixStr)
  let initbody_lambda0 = functionSetupMixedSystemsTemp(initialEquations_lambda0, &header,modelNamePrefixStr)
  let parambody = functionSetupMixedSystemsTemp(parameterEquations,&header,modelNamePrefixStr)
  let body = functionSetupMixedSystemsTemp(allEquations,&header,modelNamePrefixStr)
  let jacobianbody = ((jacobianMatrices |> JAC_MATRIX(columns=clst) => (clst |> JAC_COLUMN(columnEqns=cEqns) => functionSetupMixedSystemsTemp(cEqns,&header,modelNamePrefixStr);separator="\n") ;separator="\n"))
  <<
  /* initial mixed systems */
  <%initbody%>
  /* initial_lambda0 mixed systems */
  <%initbody_lambda0%>
  /* parameter mixed systems */
  <%parambody%>
  /* model mixed systems */
  <%body%>
  /* jacobians mixed systems */
  <%jacobianbody%>
  >>
end functionSetupMixedSystems;

template functionSetupMixedSystemsTemp(list<SimEqSystem> allEquations, Text &header, String modelNamePrefixStr)
  "Generates functions in simulation file."
::=
let &sub = buffer ""
  (allEquations |> eqn => (match eqn
     case eq as SES_MIXED(__) then
       let contEqsIndex = equationIndex(cont)
       let solvedContinuous =
         match cont
           // no dynamic tearing
           case SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing=NONE()) then
             'data->simulationInfo->linearSystemData[<%ls.indexLinearSystem%>].solved'
           case SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__), alternativeTearing=NONE()) then
             'data->simulationInfo->nonlinearSystemData[<%nls.indexNonLinearSystem%>].solved'
           // dynamic tearing
           case SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing = SOME(at as LINEARSYSTEM(__))) then
             <<
               data->simulationInfo->linearSystemData[<%ls.indexLinearSystem%>].solved'
               data->simulationInfo->linearSystemData[<%at.indexLinearSystem%>].solved'
             >>
           case SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__), alternativeTearing = SOME(at as NONLINEARSYSTEM(__))) then
             <<
               data->simulationInfo->nonlinearSystemData[<%nls.indexNonLinearSystem%>].solved
               data->simulationInfo->nonlinearSystemData[<%at.indexNonLinearSystem%>].solved
             >>
       let &preDisc = buffer ""
       let &varDecls = buffer ""
       let &auxFunction = buffer ""
       let discExp = (discEqs |> SES_SIMPLE_ASSIGN(__) hasindex i0 =>
          let expPart = daeExp(exp, contextSimulationDiscrete, &preDisc, &varDecls, &auxFunction)
          <<
          <%cref(cref, &sub)%> = <%expPart%>;
          >>
        ;separator="\n")
       let &header += 'void updateContinuousPart<%index%>(DATA* data);<%\n%>void updateIterationExpMixedSystem<%index%>(DATA* data);<%\n%>'
       <<
       <%auxFunction%>
       void updateContinuousPart<%index%>(DATA* data)
       {
         <%symbolName(modelNamePrefixStr,"eqFunction")%>_<%contEqsIndex%>(data, threadData);
         data->simulationInfo->mixedSystemData[<%indexMixedSystem%>].continuous_solution = <%solvedContinuous%>;
       }

       void updateIterationExpMixedSystem<%index%>(DATA* data)
       {
         <%varDecls%>

         <%preDisc%>
         <%discExp%>
       }
       >>
   )
   ;separator="\n\n")
end functionSetupMixedSystemsTemp;


template functionInitialLinearSystems(list<SimEqSystem> linearSystems, String modelNamePrefix)
  "Generates functions in simulation file."
::=
  let &tempeqns = buffer ""
  let &tempeqns += (linearSystems |> eq => match eq case eq as SES_LINEAR(alternativeTearing = SOME(__)) then 'int <%symbolName(modelNamePrefix,"eqFunction")%>_<%equationIndex(eq)%>(DATA*);' ; separator = "\n")
  let &globalConstraintsFunctions = buffer ""
  let linearbody = functionInitialLinearSystemsTemp(linearSystems, modelNamePrefix, &globalConstraintsFunctions)
  <<
  /* Prototypes for the strict sets (Dynamic Tearing) */
  <%tempeqns%>

  /* Global constraints for the casual sets */
  <%globalConstraintsFunctions%>
  /* function initialize linear systems */
  void <%symbolName(modelNamePrefix,"initialLinearSystem")%>(int nLinearSystems, LINEAR_SYSTEM_DATA* linearSystemData)
  {
    /* linear systems */
    <%linearbody%>
  }
  >>
end functionInitialLinearSystems;

template functionInitialLinearSystemsTemp(list<SimEqSystem> linearSystems, String modelNamePrefix, Text &globalConstraintsFunctions)
  "Generates functions in simulation file."
::=
  (linearSystems |> eqn => (match eqn
     // Mixed system
     case eq as SES_MIXED(__) then functionInitialLinearSystemsTemp(fill(eq.cont,1), modelNamePrefix, "")

     // No dynamic tearing
     case eq as SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing=NONE()) then
       match ls.jacobianMatrix
         case NONE() then
           let size = listLength(ls.vars)
           let nnz = listLength(ls.simJac)
           <<
           assertStreamPrint(NULL, nLinearSystems > <%ls.indexLinearSystem%>, "Internal Error: nLinearSystems mismatch!");
           linearSystemData[<%ls.indexLinearSystem%>].equationIndex = <%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].size = <%size%>;
           linearSystemData[<%ls.indexLinearSystem%>].nnz = <%nnz%>;
           linearSystemData[<%ls.indexLinearSystem%>].method = 0;   /* No symbolic Jacobian available */
           linearSystemData[<%ls.indexLinearSystem%>].strictTearingFunctionCall = NULL;
           linearSystemData[<%ls.indexLinearSystem%>].setA = setLinearMatrixA<%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].setb = setLinearVectorb<%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].initializeStaticLSData = initializeStaticLSData<%ls.index%>;
           >>
         case SOME(__) then
           let size = listLength(ls.vars)
           let nnz = listLength(ls.simJac)
           let generatedJac = match ls.jacobianMatrix case SOME(JAC_MATRIX(matrixName=name)) then '<%symbolName(modelNamePrefix,"functionJac")%><%name%>_column' case NONE() then 'NULL'
           let initialJac = match ls.jacobianMatrix case SOME(JAC_MATRIX(matrixName=name))then '<%symbolName(modelNamePrefix,"initialAnalyticJacobian")%><%name%>' case NONE() then 'NULL'
           let jacIndex = match ls.jacobianMatrix case SOME(JAC_MATRIX(matrixName=name, jacobianIndex=jacindex)) then '<%jacindex%> /*jacInx*/' case NONE() then '-1'
           <<
           assertStreamPrint(NULL, nLinearSystems > <%ls.indexLinearSystem%>, "Internal Error: indexlinearSystem mismatch!");
           linearSystemData[<%ls.indexLinearSystem%>].equationIndex = <%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].size = <%size%>;
           linearSystemData[<%ls.indexLinearSystem%>].nnz = <%nnz%>;
           linearSystemData[<%ls.indexLinearSystem%>].method = 1;   /* Symbolic Jacobian available */
           linearSystemData[<%ls.indexLinearSystem%>].residualFunc = residualFunc<%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].strictTearingFunctionCall = NULL;
           linearSystemData[<%ls.indexLinearSystem%>].analyticalJacobianColumn = <%generatedJac%>;
           linearSystemData[<%ls.indexLinearSystem%>].initialAnalyticalJacobian = <%initialJac%>;
           linearSystemData[<%ls.indexLinearSystem%>].jacobianIndex = <%jacIndex%>;
           linearSystemData[<%ls.indexLinearSystem%>].setA = NULL;  //setLinearMatrixA<%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].setb = NULL;  //setLinearVectorb<%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].initializeStaticLSData = initializeStaticLSData<%ls.index%>;
           >>
         else
         error(sourceInfo(), ' No jacobian create for linear system <%ls.index%>.')
       end match

     // Dynamic tearing
     case eq as SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing = SOME(at as LINEARSYSTEM(__))) then
       match ls.jacobianMatrix
         case NONE() then
           // for strict tearing set
           let size = listLength(ls.vars)
           let nnz = listLength(ls.simJac)
           // for casual tearing set
           let size2 = listLength(at.vars)
           let nnz2 = listLength(at.simJac)
           let &globalConstraintsFunctions += createGlobalConstraintsFunction(eq)
           <<
           assertStreamPrint(NULL, nLinearSystems > <%ls.indexLinearSystem%>, "Internal Error: nLinearSystems mismatch!");
           linearSystemData[<%ls.indexLinearSystem%>].equationIndex = <%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].size = <%size%>;
           linearSystemData[<%ls.indexLinearSystem%>].nnz = <%nnz%>;
           linearSystemData[<%ls.indexLinearSystem%>].method = 0;   /* No symbolic Jacobian available */
           linearSystemData[<%ls.indexLinearSystem%>].strictTearingFunctionCall = NULL;
           linearSystemData[<%ls.indexLinearSystem%>].setA = setLinearMatrixA<%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].setb = setLinearVectorb<%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].initializeStaticLSData = initializeStaticLSData<%ls.index%>;

           assertStreamPrint(NULL, nLinearSystems > <%at.indexLinearSystem%>, "Internal Error: nLinearSystems mismatch!");
           linearSystemData[<%at.indexLinearSystem%>].equationIndex = <%at.index%>;
           linearSystemData[<%at.indexLinearSystem%>].size = <%size2%>;
           linearSystemData[<%at.indexLinearSystem%>].nnz = <%nnz2%>;
           linearSystemData[<%at.indexLinearSystem%>].method = 0;   /* No symbolic Jacobian available */
           linearSystemData[<%at.indexLinearSystem%>].strictTearingFunctionCall = <%symbolName(modelNamePrefix,"eqFunction")%>_<%ls.index%>;
           linearSystemData[<%at.indexLinearSystem%>].setA = setLinearMatrixA<%at.index%>;
           linearSystemData[<%at.indexLinearSystem%>].setb = setLinearVectorb<%at.index%>;
           linearSystemData[<%at.indexLinearSystem%>].initializeStaticLSData = initializeStaticLSData<%at.index%>;
           linearSystemData[<%at.indexLinearSystem%>].checkConstraints = checkConstraints<%at.index%>;
           >>
         case SOME(__) then
           let size = listLength(ls.vars)
           let nnz = listLength(ls.simJac)
           let generatedJac = match ls.jacobianMatrix case SOME(JAC_MATRIX(matrixName=name)) then '<%symbolName(modelNamePrefix,"functionJac")%><%name%>_column' case NONE() then 'NULL'
           let initialJac = match ls.jacobianMatrix case SOME(JAC_MATRIX(matrixName=name))then '<%symbolName(modelNamePrefix,"initialAnalyticJacobian")%><%name%>' case NONE() then 'NULL'
           let jacIndex = match ls.jacobianMatrix case SOME(JAC_MATRIX(matrixName=name, jacobianIndex=jacindex)) then '<%jacindex%>' case NONE() then '-1'
           let size2 = listLength(at.vars)
           let nnz2 = listLength(at.simJac)
           let generatedJac2 = match at.jacobianMatrix case SOME(JAC_MATRIX(matrixName=name)) then '<%symbolName(modelNamePrefix,"functionJac")%><%name%>_column' case NONE() then 'NULL'
           let initialJac2 = match at.jacobianMatrix case SOME(JAC_MATRIX(matrixName=name))then '<%symbolName(modelNamePrefix,"initialAnalyticJacobian")%><%name%>' case NONE() then 'NULL'
           let jacIndex2 = match at.jacobianMatrix case SOME(JAC_MATRIX(matrixName=name, jacobianIndex=jacindex)) then '<%jacindex%>' case NONE() then '-1'
           let &globalConstraintsFunctions += createGlobalConstraintsFunction(eq)
           <<
           assertStreamPrint(NULL, nLinearSystems > <%ls.indexLinearSystem%>, "Internal Error: indexlinearSystem mismatch!");
           linearSystemData[<%ls.indexLinearSystem%>].equationIndex = <%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].size = <%size%>;
           linearSystemData[<%ls.indexLinearSystem%>].nnz = <%nnz%>;
           linearSystemData[<%ls.indexLinearSystem%>].method = 1;   /* Symbolic Jacobian available */
           linearSystemData[<%ls.indexLinearSystem%>].residualFunc = residualFunc<%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].strictTearingFunctionCall = NULL;
           linearSystemData[<%ls.indexLinearSystem%>].analyticalJacobianColumn = <%generatedJac%>;
           linearSystemData[<%ls.indexLinearSystem%>].initialAnalyticalJacobian = <%initialJac%>;
           linearSystemData[<%ls.indexLinearSystem%>].jacobianIndex = <%jacIndex%>;
           linearSystemData[<%ls.indexLinearSystem%>].setA = NULL;  //setLinearMatrixA<%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].setb = NULL;  //setLinearVectorb<%ls.index%>;
           linearSystemData[<%ls.indexLinearSystem%>].initializeStaticLSData = initializeStaticLSData<%ls.index%>;

           assertStreamPrint(NULL, nLinearSystems > <%at.indexLinearSystem%>, "Internal Error: indexlinearSystem mismatch!");
           linearSystemData[<%at.indexLinearSystem%>].equationIndex = <%at.index%>;
           linearSystemData[<%at.indexLinearSystem%>].size = <%size2%>;
           linearSystemData[<%at.indexLinearSystem%>].nnz = <%nnz2%>;
           linearSystemData[<%at.indexLinearSystem%>].method = 1;   /* Symbolic Jacobian available */
           linearSystemData[<%at.indexLinearSystem%>].residualFunc = residualFunc<%at.index%>;
           linearSystemData[<%at.indexLinearSystem%>].strictTearingFunctionCall = <%symbolName(modelNamePrefix,"eqFunction")%>_<%ls.index%>;
           linearSystemData[<%at.indexLinearSystem%>].analyticalJacobianColumn = <%generatedJac2%>;
           linearSystemData[<%at.indexLinearSystem%>].initialAnalyticalJacobian = <%initialJac2%>;
           linearSystemData[<%at.indexLinearSystem%>].jacobianIndex = <%jacIndex2%>;
           linearSystemData[<%at.indexLinearSystem%>].setA = NULL;  //setLinearMatrixA<%at.index%>;
           linearSystemData[<%at.indexLinearSystem%>].setb = NULL;  //setLinearVectorb<%at.index%>;
           linearSystemData[<%at.indexLinearSystem%>].initializeStaticLSData = initializeStaticLSData<%at.index%>;
           linearSystemData[<%at.indexLinearSystem%>].checkConstraints = checkConstraints<%at.index%>;
           >>

        // Error case
         else
         error(sourceInfo(), ' No jacobian create for linear system <%ls.index%> or <%at.index%>.')
       end match
   )
   ;separator="\n\n")
end functionInitialLinearSystemsTemp;

template functionSetupLinearSystems(list<SimEqSystem> linearSystems, String modelNamePrefix)
  "Generates functions in simulation file."
::=
  let linearbody = functionSetupLinearSystemsTemp(linearSystems, modelNamePrefix)
  <<
  /* linear systems */
  <%linearbody%>
  >>
end functionSetupLinearSystems;

template functionSetupLinearSystemsTemp(list<SimEqSystem> linearSystems, String modelNamePrefix)
  "Generates functions in simulation file."
::=
  let &sub = buffer ""
  (linearSystems |> eqn => (match eqn
     case eq as SES_MIXED(__) then functionSetupLinearSystemsTemp(fill(eq.cont,1), modelNamePrefix)
     // no dynamic tearing
     case eq as SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing=NONE()) then
     match ls.jacobianMatrix
       case SOME(__) then
         let &varDeclsRes = buffer "" /*BUFD*/
         let &auxFunction = buffer ""
         let &tmp = buffer ""
         let xlocs = (ls.vars |> var hasindex i0 => '<%cref(varName(var), &sub)%> = xloc[<%i0%>];' ;separator="\n")
         let prebody = (match ls.partOfJac
           case true then
             (ls.residual |> eq2 =>
               functionExtraResidualsPreBodyJacobian(eq2, &tmp, modelNamePrefix)
             ;separator="\n")
           case false then
             (ls.residual |> eq2 =>
               functionExtraResidualsPreBody(eq2, &tmp, modelNamePrefix)
             ;separator="\n")
           end match)
         let body = (ls.residual |> eq2 hasindex i0 => match eq2
            case SES_RESIDUAL(__) then
              let &preExp = buffer "" /*BUFD*/
              let expPart = daeExp(exp, contextSimulationDiscrete,
                              &preExp /*BUFC*/, &varDeclsRes, &auxFunction)
              <<
              <% if profileAll() then 'SIM_PROF_TICK_EQ(<%index%>);' %>
              <%preExp%>res[<%i0%>] = <%expPart%>;
              <% if profileAll() then 'SIM_PROF_ACC_EQ(<%index%>);' %>
              >>
            case SES_FOR_RESIDUAL(__) then "case 1"
          ;separator="\n")
       <<
       <%auxFunction%>
       <%tmp%>

       void residualFunc<%ls.index%>(RESIDUAL_USERDATA* userData, const double* xloc, double* res, const int* iflag)
       {
         TRACE_PUSH
         DATA *data = userData->data;
         threadData_t *threadData = userData->threadData;
         const int equationIndexes[2] = {1,<%ls.index%>};
         <% if ls.partOfJac then
           'ANALYTIC_JACOBIAN* parentJacobian = data->simulationInfo->linearSystemData[<%ls.indexLinearSystem%>].parDynamicData[omc_get_thread_num()].parentJacobian;'
         %>
         ANALYTIC_JACOBIAN* jacobian = NULL;
         <%varDeclsRes%>
         <% if profileAll() then 'SIM_PROF_TICK_EQ(<%ls.index%>);' %>
         <% if profileSome() then 'SIM_PROF_ADD_NCALL_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%ls.index%>).profileBlockIndex,1);' %>
         <%xlocs%>
         <%prebody%>
         <%body%>
         <% if profileAll() then 'SIM_PROF_ACC_EQ(<%ls.index%>);' %>
         TRACE_POP
       }
       OMC_DISABLE_OPT
       <%initializeStaticLSVars(ls.vars, ls.index)%>
       >>
       else
         let &varDecls = buffer "" /*BUFD*/
         let &auxFunction = buffer ""
         let MatrixA = (ls.simJac |> (row, col, eq) hasindex i0 => match eq
            case SES_RESIDUAL(__) then
              let &preExp = buffer "" /*BUFD*/
              let expPart = daeExp(exp, contextSimulationDiscrete, &preExp,  &varDecls, &auxFunction)
              '<%preExp%>linearSystemData->setAElement(<%row%>, <%col%>, <%expPart%>, <%i0%>, linearSystemData, threadData);'
            case SES_FOR_RESIDUAL(__) then "case 2"
          ;separator="\n")

         let &varDecls2 = buffer "" /*BUFD*/
         let vectorb = (ls.beqs |> exp hasindex i0 =>
           let &preExp = buffer "" /*BUFD*/
           let expPart = daeExp(exp, contextSimulationDiscrete, &preExp, &varDecls2, &auxFunction)
             '<%preExp%>linearSystemData->setBElement(<%i0%>, <%expPart%>, linearSystemData, threadData);'
          ;separator="\n")
       <<
       <%auxFunction%>
       OMC_DISABLE_OPT
       void setLinearMatrixA<%ls.index%>(DATA* data, threadData_t* threadData, LINEAR_SYSTEM_DATA* linearSystemData)
       {
         const int equationIndexes[2] = {1,<%ls.index%>};
         <% if ls.partOfJac then 'ANALYTIC_JACOBIAN* parentJacobian = linearSystemData->parDynamicData[omc_get_thread_num()].parentJacobian;'%>
         <%varDecls%>
         <%MatrixA%>
       }
       OMC_DISABLE_OPT
       void setLinearVectorb<%ls.index%>(DATA* data, threadData_t* threadData, LINEAR_SYSTEM_DATA* linearSystemData)
       {
         const int equationIndexes[2] = {1,<%ls.index%>};
         <% if ls.partOfJac then 'ANALYTIC_JACOBIAN* parentJacobian = linearSystemData->parDynamicData[omc_get_thread_num()].parentJacobian;'%>
         <%varDecls2%>
         <%vectorb%>
       }
       OMC_DISABLE_OPT
       <%initializeStaticLSVars(ls.vars, ls.index)%>
       >>
     end match

     // dynamic tearing
     case eq as SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing = SOME(at as LINEARSYSTEM(__))) then
     match ls.jacobianMatrix
       case SOME(__) then
         // for strict tearing set
         let &sub = buffer ""
         let &varDeclsRes = buffer "" /*BUFD*/
         let &auxFunction = buffer ""
         let &tmp = buffer ""
         let xlocs = (ls.vars |> var hasindex i0 => '<%cref(varName(var), &sub)%> = xloc[<%i0%>];' ;separator="\n")
         let prebody = (ls.residual |> eq2 =>
               functionExtraResidualsPreBody(eq2, &tmp, modelNamePrefix)
          ;separator="\n")
         let body = (ls.residual |> eq2 hasindex i0 => match eq2
            case SES_RESIDUAL(__) then
              let &preExp = buffer "" /*BUFD*/
              let expPart = daeExp(exp, contextSimulationDiscrete,
                              &preExp /*BUFC*/, &varDeclsRes, &auxFunction)
              <<
              <% if profileAll() then 'SIM_PROF_TICK_EQ(<%index%>);' %>
              <%preExp%>res[<%i0%>] = <%expPart%>;
              <% if profileAll() then 'SIM_PROF_ACC_EQ(<%index%>);' %>
              >>
            case SES_FOR_RESIDUAL(__) then "case 3"
           ;separator="\n")
         // for casual tearing set
         let &varDeclsRes2 = buffer "" /*BUFD*/
         let &auxFunction2 = buffer ""
         let &tmp2 = buffer ""
         let xlocs2 = (at.vars |> var hasindex i0 => '<%cref(varName(var), &sub)%> = xloc[<%i0%>];' ;separator="\n")
         let prebody2 = (at.residual |> eq2 =>
               functionExtraResidualsPreBody(eq2, &tmp2, modelNamePrefix)
          ;separator="\n")
         let body2 = (at.residual |> eq2 hasindex i0 => match eq2
           case SES_RESIDUAL(__) then
             let &preExp2 = buffer "" /*BUFD*/
             let expPart2 = daeExp(exp, contextSimulationDiscrete,
                              &preExp2 /*BUFC*/, &varDeclsRes2, &auxFunction2)
             <<
             <% if profileAll() then 'SIM_PROF_TICK_EQ(<%index%>);' %>
             <%preExp2%>res[<%i0%>] = <%expPart2%>;
             <% if profileAll() then 'SIM_PROF_ACC_EQ(<%index%>);' %>
             >>
            case SES_FOR_RESIDUAL(__) then "case 4"
           ;separator="\n")
       <<
       <%auxFunction%>
       <%tmp%>

       void residualFunc<%ls.index%>(RESIDUAL_USERDATA* userData, const double* xloc, double* res, const int* iflag)
       {
         TRACE_PUSH
         DATA *data = userData->data;
         threadData_t *threadData = userData->threadData;
         const int equationIndexes[2] = {1,<%ls.index%>};
         <% if ls.partOfJac then
           'ANALYTIC_JACOBIAN* parentJacobian = data->simulationInfo->linearSystemData[<%ls.indexLinearSystem%>].parDynamicData[omc_get_thread_num()].parentJacobian;'
         %>
         ANALYTIC_JACOBIAN* jacobian = NULL;
         <%varDeclsRes%>
         <% if profileAll() then 'SIM_PROF_TICK_EQ(<%ls.index%>);' %>
         <% if profileSome() then 'SIM_PROF_ADD_NCALL_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%ls.index%>).profileBlockIndex,1);' %>
         <%xlocs%>
         <%prebody%>
         <%body%>
         <% if profileAll() then 'SIM_PROF_ACC_EQ(<%ls.index%>);' %>
         TRACE_POP
       }
       OMC_DISABLE_OPT
       <%initializeStaticLSVars(ls.vars, ls.index)%>

       <%auxFunction2%>
       <%tmp2%>

       void residualFunc<%at.index%>(RESIDUAL_USERDATA* userData, const double* xloc, double* res, const int* iflag)
       {
         TRACE_PUSH
         DATA *data = userData->data;
         threadData_t *threadData = userData->threadData;
         const int equationIndexes[2] = {1,<%at.index%>};
         <% if ls.partOfJac then
           'ANALYTIC_JACOBIAN* parentJacobian = data->simulationInfo->linearSystemData[<%ls.indexLinearSystem%>].parDynamicData[omc_get_thread_num()].parentJacobian;'
         %>
         ANALYTIC_JACOBIAN* jacobian = NULL;
         <%varDeclsRes2%>
         <% if profileAll() then 'SIM_PROF_TICK_EQ(<%at.index%>);' %>
         <% if profileSome() then 'SIM_PROF_ADD_NCALL_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%at.index%>).profileBlockIndex,1);' %>
         <%xlocs2%>
         <%prebody2%>
         <%body2%>
         <% if profileAll() then 'SIM_PROF_ACC_EQ(<%at.index%>);' %>
         TRACE_POP
       }
       OMC_DISABLE_OPT
       <%initializeStaticLSVars(at.vars, at.index)%>
       >>
       else
         // for strict tearing set
         let &varDecls = buffer "" /*BUFD*/
         let &auxFunction = buffer ""
         let MatrixA = (ls.simJac |> (row, col, eq) hasindex i0 => match eq
           case SES_RESIDUAL(__) then
             let &preExp = buffer "" /*BUFD*/
             let expPart = daeExp(exp, contextSimulationDiscrete, &preExp,  &varDecls, &auxFunction)
               '<%preExp%>linearSystemData->setAElement(<%row%>, <%col%>, <%expPart%>, <%i0%>, linearSystemData, threadData);'
           case SES_FOR_RESIDUAL(__) then "case 5"
          ;separator="\n")

         let &varDecls2 = buffer "" /*BUFD*/
         let vectorb = (ls.beqs |> exp hasindex i0 =>
           let &preExp = buffer "" /*BUFD*/
           let expPart = daeExp(exp, contextSimulationDiscrete, &preExp, &varDecls2, &auxFunction)
             '<%preExp%>linearSystemData->setBElement(<%i0%>, <%expPart%>, linearSystemData, threadData);'
          ;separator="\n")
         // for casual tearing set
         let &varDecls3 = buffer "" /*BUFD*/
         let &auxFunction2 = buffer ""
         let MatrixA2 = (at.simJac |> (row, col, eq) hasindex i0 => match eq
           case SES_RESIDUAL(__) then
             let &preExp3 = buffer "" /*BUFD*/
             let expPart3 = daeExp(exp, contextSimulationDiscrete, &preExp3,  &varDecls3, &auxFunction2)
               '<%preExp3%>linearSystemData->setAElement(<%row%>, <%col%>, <%expPart3%>, <%i0%>, linearSystemData, threadData);'
           case SES_FOR_RESIDUAL(__) then "case 6"
          ;separator="\n")

         let &varDecls4 = buffer "" /*BUFD*/
         let vectorb2 = (at.beqs |> exp hasindex i0 =>
           let &preExp4 = buffer "" /*BUFD*/
           let expPart4 = daeExp(exp, contextSimulationDiscrete, &preExp4, &varDecls4, &auxFunction2)
             '<%preExp4%>linearSystemData->setBElement(<%i0%>, <%expPart4%>, linearSystemData, threadData);'
           ;separator="\n")
       <<
       <%auxFunction%>
       OMC_DISABLE_OPT
       void setLinearMatrixA<%ls.index%>(DATA* data, LINEAR_SYSTEM_DATA *linearSystemData)
       {
         const int equationIndexes[2] = {1,<%ls.index%>};
         <% if ls.partOfJac then 'ANALYTIC_JACOBIAN* parentJacobian = linearSystemData->parDynamicData[omc_get_thread_num()].parentJacobian;'%>
         <%varDecls%>
         <%MatrixA%>
       }
       OMC_DISABLE_OPT
       void setLinearVectorb<%ls.index%>(DATA* data, LINEAR_SYSTEM_DATA* linearSystemData)
       {
         const int equationIndexes[2] = {1,<%ls.index%>};
         <% if ls.partOfJac then 'ANALYTIC_JACOBIAN* parentJacobian = linearSystemData->parDynamicData[omc_get_thread_num()].parentJacobian;'%>
         <%varDecls2%>
         <%vectorb%>
       }
       OMC_DISABLE_OPT
       <%initializeStaticLSVars(ls.vars, ls.index)%>

       <%auxFunction2%>
       OMC_DISABLE_OPT
       void setLinearMatrixA<%at.index%>(DATA* data, LINEAR_SYSTEM_DATA* linearSystemData)
       {
         const int equationIndexes[2] = {1,<%at.index%>};
         <% if ls.partOfJac then 'ANALYTIC_JACOBIAN* parentJacobian = linearSystemData->parDynamicData[omc_get_thread_num()].parentJacobian;'%>
         <%varDecls3%>
         <%MatrixA2%>
       }
       OMC_DISABLE_OPT
       void setLinearVectorb<%at.index%>(DATA* data, LINEAR_SYSTEM_DATA* linearSystemData)
       {
         const int equationIndexes[2] = {1,<%at.index%>};
         <% if ls.partOfJac then 'ANALYTIC_JACOBIAN* parentJacobian = linearSystemData->parDynamicData[omc_get_thread_num()].parentJacobian;'%>
         <%varDecls4%>
         <%vectorb2%>
       }
       OMC_DISABLE_OPT
       <%initializeStaticLSVars(at.vars, at.index)%>
       >>
     end match
   )
   ;separator="\n\n")
end functionSetupLinearSystemsTemp;

template functionInitialNonLinearSystems(list<SimEqSystem> nonlinearSystems, String modelNamePrefix)
  "Generates functions in simulation file."
::=
  let &tempeqns = buffer ""
  let &tempeqns += (nonlinearSystems |> eq => match eq case eq as SES_NONLINEAR(alternativeTearing = SOME(__)) then 'int <%symbolName(modelNamePrefix,"eqFunction")%>_<%equationIndex(eq)%>(DATA*, threadData_t*);' ; separator = "\n")
  let &globalConstraintsFunctions = buffer ""
  let nlsbody = functionInitialNonLinearSystemsTemp(nonlinearSystems, modelNamePrefix, &globalConstraintsFunctions)
  <<
  /* Prototypes for the strict sets (Dynamic Tearing) */
  <%tempeqns%>

  /* Global constraints for the casual sets */
  <%globalConstraintsFunctions%>
  /* function initialize non-linear systems */
  void <%symbolName(modelNamePrefix,"initialNonLinearSystem")%>(int nNonLinearSystems, NONLINEAR_SYSTEM_DATA* nonLinearSystemData)
  {
    <%nlsbody%>
  }
  >>
end functionInitialNonLinearSystems;

template functionInitialNonLinearSystemsTemp(list<SimEqSystem> nonlinearSystems, String modelPrefixName, Text &globalConstraintsFunctions)
  "Generates functions in simulation file."
::=
  (nonlinearSystems |> eqn => (match eqn
     case eq as SES_MIXED(__) then functionInitialNonLinearSystemsTemp(fill(eq.cont,1), modelPrefixName, &globalConstraintsFunctions)
     // no dynamic tearing
     case eq as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__), alternativeTearing=NONE()) then
       let system = generateNonLinearSystemData(nls, 0, modelPrefixName)
       <<
       <%system%>
       >>
     // dynamic tearing
     case eq as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__), alternativeTearing = SOME(at as NONLINEARSYSTEM(__))) then
       let system = generateNonLinearSystemData(nls, 0, modelPrefixName)
       let systemCasual = generateNonLinearSystemData(at, nls.index, modelPrefixName)
       let &globalConstraintsFunctions += createGlobalConstraintsFunction(eq)
       <<
       <%system%>
       <%systemCasual%>
       >>
     )
   ;separator="\n\n")
end functionInitialNonLinearSystemsTemp;

template generateNonLinearSystemData(NonlinearSystem system, Integer indexStrict, String modelPrefixName)
  "Generates nonlinear system data.
   indexStrict = 0: no dynamic tearing or strict set,
   else: casual set and indexStrict is the index of the corresponding strict set"
::=
  match system
    case nls as NONLINEARSYSTEM(__) then
      let size = listLength(nls.crefs)
      let generatedJac = match nls.jacobianMatrix case SOME(JAC_MATRIX(columns={},matrixName=name)) then 'NULL' case SOME(JAC_MATRIX(matrixName=name)) then '<%symbolName(modelPrefixName,"functionJac")%><%name%>_column' case NONE() then 'NULL'
      let initialJac = match nls.jacobianMatrix case SOME(JAC_MATRIX(columns={},matrixName=name)) then 'NULL' case SOME(JAC_MATRIX(matrixName=name)) then '<%symbolName(modelPrefixName,"initialAnalyticJacobian")%><%name%>' case NONE() then 'NULL'
      let jacIndex = match nls.jacobianMatrix case SOME(JAC_MATRIX(columns={}, matrixName=name)) then '-1' case SOME(JAC_MATRIX(matrixName=name, jacobianIndex=jacindex)) then  '<%jacindex%> /*jacInx*/' case NONE() then '-1'
      let innerSystems = functionInitialNonLinearSystemsTemp(nls.eqs, modelPrefixName, "")
      let casualCall = if not intEq(indexStrict, 0) then '<%symbolName(modelPrefixName,"eqFunction")%>_<%indexStrict%>' else 'NULL'
      let constraintsCall = if not intEq(indexStrict, 0) then 'checkConstraints<%nls.index%>' else 'NULL'
      let residualCall = if intEq(indexStrict, 0) then
                           'nonLinearSystemData[<%nls.indexNonLinearSystem%>].residualFunc = residualFunc<%nls.index%>;'
                         else
                           'nonLinearSystemData[<%nls.indexNonLinearSystem%>].residualFuncConstraints = residualFuncConstraints<%nls.index%>;'
      <<
      <%innerSystems%>

      nonLinearSystemData[<%nls.indexNonLinearSystem%>].equationIndex = <%nls.index%>;
      nonLinearSystemData[<%nls.indexNonLinearSystem%>].size = <%size%>;
      nonLinearSystemData[<%nls.indexNonLinearSystem%>].homotopySupport = <%boolStrC(nls.homotopySupport)%>;
      nonLinearSystemData[<%nls.indexNonLinearSystem%>].mixedSystem = <%boolStrC(nls.mixedSystem)%>;
      <%residualCall%>
      nonLinearSystemData[<%nls.indexNonLinearSystem%>].strictTearingFunctionCall = <%casualCall%>;
      nonLinearSystemData[<%nls.indexNonLinearSystem%>].analyticalJacobianColumn = <%generatedJac%>;
      nonLinearSystemData[<%nls.indexNonLinearSystem%>].initialAnalyticalJacobian = <%initialJac%>;
      nonLinearSystemData[<%nls.indexNonLinearSystem%>].jacobianIndex = <%jacIndex%>;
      nonLinearSystemData[<%nls.indexNonLinearSystem%>].initializeStaticNLSData = initializeStaticDataNLS<%nls.index%>;
      nonLinearSystemData[<%nls.indexNonLinearSystem%>].freeStaticNLSData = freeStaticDataNLS<%nls.index%>;
      nonLinearSystemData[<%nls.indexNonLinearSystem%>].getIterationVars = getIterationVarsNLS<%nls.index%>;
      nonLinearSystemData[<%nls.indexNonLinearSystem%>].checkConstraints = <%constraintsCall%>;
      >>
end generateNonLinearSystemData;

template createGlobalConstraintsFunction(SimEqSystem system)
  "Creates a function which is called before each evaluation of the casual set to make sure that the constraints are not violated."
::=
   match system
     case SES_NONLINEAR(alternativeTearing = SOME(at as NONLINEARSYSTEM(__))) then
       let constraints = createGlobalConstraints(at.eqs)
       <<
       int checkConstraints<%at.index%>(DATA *data, threadData_t *threadData)
       {
         const int equationIndexes[2] = {1,<%at.index%>};
         <%constraints%>
         return 1;
       }

       >>

     case SES_LINEAR(alternativeTearing = SOME(at as LINEARSYSTEM(__))) then
       let constraints = createGlobalConstraints(at.residual)
       <<
       int checkConstraints<%at.index%>(DATA *data, threadData_t *threadData)
       {
         const int equationIndexes[2] = {1,<%at.index%>};
         <%constraints%>
         return 1;
       }

       >>
end createGlobalConstraintsFunction;

template createGlobalConstraints(list<SimEqSystem> innerEqns)
  "Creates a single constraint from SES_SIMPLE_ASSIGN_CONSTRAINTS which must not be violated to use the casual set."
::=
   (innerEqns |> innerEqn => (match innerEqn
     case innerEqn as SES_SIMPLE_ASSIGN_CONSTRAINTS(__) then
       (innerEqn.cons |> con => (match con
         case con as DAE.CONSTRAINT_DT(constraint = c, localCon = localCon) then
           let &preExp = buffer ""
           let &varDecls = buffer ""
           let &auxFunction = buffer ""
           let condition = daeExp(c, contextSimulationDiscrete, &preExp, &varDecls, &auxFunction)
           <<
           <%varDecls%>
           <%auxFunction%>
           <%preExp%>
           if (!<%condition%>){
             debugString(LOG_DT_CONS, "The following <%if localCon then "local" else "global"%> constraint is violated:\n<%dumpExp(c,"\"")%>");
             return 0;
           }
           >>
         )
       ;separator="\n")
     )
   ;separator="\n")
end createGlobalConstraints;

template functionExtraResidualsPreBody(SimEqSystem eq, Text &eqs, String modelNamePrefixStr)
 "Generates an equation."
::=
  let () = tmpTickReset(0)
  match eq
  case e as SES_RESIDUAL(__)
   then ""
  case e as SES_FOR_RESIDUAL(__)
   then ""
  case e as SES_GENERIC_RESIDUAL(__)
   then ""
  else
    let &eqs += equation_impl(-1, -1, eq, contextSimulationDiscrete, modelNamePrefixStr, false)
    <<
    /* local constraints */
    <%createLocalConstraints(eq)%>
    <%equation_call(eq, modelNamePrefixStr)%>
    >>
  end match
end functionExtraResidualsPreBody;

template functionExtraResidualsPreBodyJacobian(SimEqSystem eq, Text &eqs, String modelNamePrefixStr)
 "Generates an equation."
::=
  let () = tmpTickReset(0)
  match eq
  case e as SES_RESIDUAL(__)
   then ""
  case e as SES_FOR_RESIDUAL(__)
   then ""
  case e as SES_GENERIC_RESIDUAL(__)
   then ""
  else
    let &eqs += equation_impl(-1, -1, eq, contextJacobian, modelNamePrefixStr, false)
    <<
    /* local constraints */
    <%createLocalConstraints(eq)%>
    <%equation_callJacobian(eq, modelNamePrefixStr)%>
    >>
  end match
end functionExtraResidualsPreBodyJacobian;

template createLocalConstraints(SimEqSystem eq)
 "Generates an equation."
::=
  match eq
  case e as SES_SIMPLE_ASSIGN_CONSTRAINTS(__) then
    (e.cons |> con => (match con
      case con as DAE.CONSTRAINT_DT(constraint = c, localCon = true) then
        let &preExp = buffer ""
        let &varDecls = buffer ""
        let &auxFunction = buffer ""
        let condition = daeExp(c, contextSimulationDiscrete, &preExp, &varDecls, &auxFunction)
        <<
        <%varDecls%>
        <%auxFunction%>
        <%preExp%>
        if (!<%condition%>){
          debugString(LOG_DT_CONS, "The following local constraint is violated:\n<%dumpExp(c,"\"")%>");
          debugString(LOG_DT, "Local constraints of the casual tearing set are violated! Let's fail...");
          return 1;
        }
        >>
      )
      ;separator="\n")
   end match
end createLocalConstraints;

template functionNonLinearResidualsMultiFile(list<SimEqSystem> nonlinearSystems, Integer equationsPerFile, String fullPathPrefix, String fileNamePrefix, String partName, String modelNamePrefix)
  "Generates functions in simulation file."
::=
  functionNonLinearResidualsMultiFile2(SimCodeUtil.unbalancedEqSystemPartition(selectNLEqSys(nonlinearSystems), equationsPerFile), fullPathPrefix, fileNamePrefix, partName, modelNamePrefix)
end functionNonLinearResidualsMultiFile;

template functionNonLinearResidualsMultiFile2(list<list<SimEqSystem>> nonlinearSystems, String fullPathPrefix, String fileNamePrefix, String partName, String modelNamePrefix)
  "Generates functions in simulation file."
::=
  match nonlinearSystems
  case {} then ""
  case {eqs} then
    let &prototypes = buffer ""
    functionNonLinearResiduals(eqs, modelNamePrefix, &prototypes)
  else
    let &prototypes = buffer ""
    let &file = buffer ""
    let &file +=
    (nonlinearSystems |> eqs =>
      let fileName = addFunctionIndex('<%fileNamePrefix%>_<%partName%>_part', ".c")
      redirectToFile(fullPathPrefix + fileName) +
      <<
      /* Non Linear Systems <%fullPathPrefix + fileName%> */
      <%simulationFileHeader(fileNamePrefix)%>
      #include "<%fileNamePrefix%>_12jac.h"
      #if defined(__cplusplus)
      extern "C" {
      #endif
      <%functionNonLinearResiduals(eqs, modelNamePrefix, &prototypes)%>
      #if defined(__cplusplus)
      }
      #endif
      <%\n%>
      >>
      + closeFile()
    )
    prototypes + file
end functionNonLinearResidualsMultiFile2;

template getNLSPrototypes(Integer index)
::=
  <<
  void residualFunc<%index%>(RESIDUAL_USERDATA* userData, const double* xloc, double* res, const int* iflag);
  void initializeStaticDataNLS<%index%>(DATA* data, threadData_t *threadData, NONLINEAR_SYSTEM_DATA *inSystemData, modelica_boolean initSparsePattern, modelica_boolean initNonlinearPattern);
  void freeSparsePatternNLS<%index%>(NONLINEAR_SYSTEM_DATA *inSystemData);
  void freeStaticDataNLS<%index%>(DATA* data, threadData_t *threadData, NONLINEAR_SYSTEM_DATA *inSystemData);
  void getIterationVarsNLS<%index%>(DATA* data, double *array);
  >>
end getNLSPrototypes;

template functionNonLinearResiduals(list<SimEqSystem> nonlinearSystems, String modelNamePrefix, Text &prototypes)
  "Generates functions in simulation file."
::=
  (nonlinearSystems |> eqn => (
    let () = tmpTickReset(0)
    match eqn
    case eq as SES_MIXED(__) then functionNonLinearResiduals(fill(eq.cont,1),modelNamePrefix,prototypes)
    // no dynamic tearing
    case eq as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(
        jacobianMatrix=SOME(JAC_MATRIX(sparsity=sparsePattern,nonlinear=nonlinearPattern,nonlinearT=nonlinearPatternT,
        coloredCols=colorList,maxColorCols=maxColor))),
        alternativeTearing=NONE()) then
      let residualFunction = generateNonLinearResidualFunction(nls, modelNamePrefix, 0)
      let indexName = 'NLS<%nls.index%>'
      let sparseData = generateStaticSparseData(indexName, 'NONLINEAR_SYSTEM_DATA', sparsePattern, colorList, maxColor)
      let nonlinearData = generateStaticNonlinearData(indexName, 'NONLINEAR_SYSTEM_DATA', nonlinearPattern, nonlinearPatternT)
      let bodyStaticData = generateStaticInitialData(nls.crefs, indexName)
      let updateIterationVars = getIterationVars(nls.crefs, indexName)
      let &prototypes += getNLSPrototypes(nls.index)
      <<
      <%residualFunction%>
      <%sparseData%>
      <%nonlinearData%>
      <%bodyStaticData%>
      <%updateIterationVars%>
      >>
    case eq as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__),alternativeTearing=NONE()) then
      let residualFunction = generateNonLinearResidualFunction(nls, modelNamePrefix, 0)
      let indexName = 'NLS<%nls.index%>'
      let sparseData = generateStaticEmptySparseData(indexName, 'NONLINEAR_SYSTEM_DATA')
      let nonlinearData = generateStaticEmptyNonlinearData(indexName, 'NONLINEAR_SYSTEM_DATA')
      let bodyStaticData = generateStaticInitialData(nls.crefs, indexName)
      let updateIterationVars = getIterationVars(nls.crefs, indexName)
      let &prototypes += getNLSPrototypes(nls.index)
      <<
      <%residualFunction%>
      <%sparseData%>
      <%nonlinearData%>
      <%bodyStaticData%>
      <%updateIterationVars%>
      >>
    // dynamic tearing
    case eq as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(
        jacobianMatrix=SOME(JAC_MATRIX(sparsity=sparsePattern,nonlinear=nonlinearPattern,nonlinearT=nonlinearPatternT,coloredCols=colorList,maxColorCols=maxColor))),
        alternativeTearing = SOME(at as NONLINEARSYSTEM(
        jacobianMatrix=SOME(JAC_MATRIX(sparsity=sparsePattern2,coloredCols=colorList2,maxColorCols=maxColor2))))
        ) then
      // for strict tearing set
      let residualFunction = generateNonLinearResidualFunction(nls, modelNamePrefix, 0)
      let indexName = 'NLS<%nls.index%>'
      let sparseData = generateStaticSparseData(indexName, 'NONLINEAR_SYSTEM_DATA', sparsePattern, colorList, maxColor)
      let nonlinearData = generateStaticNonlinearData(indexName, 'NONLINEAR_SYSTEM_DATA', nonlinearPattern, nonlinearPatternT)
      let bodyStaticData = generateStaticInitialData(nls.crefs, indexName)
      let updateIterationVars = getIterationVars(nls.crefs, indexName)
      // for casual tearing set
      let residualFunctionCasual = generateNonLinearResidualFunction(at, modelNamePrefix, 1)
      let indexName = 'NLS<%at.index%>'
      let sparseDataCasual = generateStaticSparseData(indexName, 'NONLINEAR_SYSTEM_DATA', sparsePattern, colorList, maxColor)
      let nonlinearDataCasual = generateStaticNonlinearData(indexName, 'NONLINEAR_SYSTEM_DATA', nonlinearPattern, nonlinearPatternT)
      let bodyStaticDataCasual = generateStaticInitialData(at.crefs, indexName)
      let updateIterationVarsCasual = getIterationVars(at.crefs, indexName)
      let &prototypes += getNLSPrototypes(nls.index)
      <<
      /* start residuals for dynamic tearing sets */
      /* strict tearing set */
      <%residualFunction%>
      <%sparseData%>
      <%nonlinearData%>
      <%bodyStaticData%>
      <%updateIterationVars%>
      /* casual tearing set */
      <%residualFunctionCasual%>
      <%sparseDataCasual%>
      <%nonlinearDataCasual%>
      <%bodyStaticDataCasual%>
      <%updateIterationVarsCasual%>
      /* end residuals for dynamic tearing sets */
      >>
    case eq as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__),
        alternativeTearing = SOME(at as NONLINEARSYSTEM(__))
        ) then
      // for strict tearing set
      let residualFunction = generateNonLinearResidualFunction(nls, modelNamePrefix, 0)
      let indexName = 'NLS<%nls.index%>'
      let sparseData = generateStaticEmptySparseData(indexName, 'NONLINEAR_SYSTEM_DATA')
      let bodyStaticData = generateStaticInitialData(nls.crefs, indexName)
      let updateIterationVars = getIterationVars(nls.crefs, indexName)
      // for casual tearing set
      let residualFunctionCasual = generateNonLinearResidualFunction(at, modelNamePrefix, 1)
      let indexName = 'NLS<%at.index%>'
      let sparseDataCasual = generateStaticEmptySparseData(indexName, 'NONLINEAR_SYSTEM_DATA')
      let bodyStaticDataCasual = generateStaticInitialData(at.crefs, indexName)
      let updateIterationVarsCasual = getIterationVars(at.crefs, indexName)
      let &prototypes += getNLSPrototypes(nls.index)
      <<
      /* start residuals for dynamic tearing sets */
      /* strict tearing set */
      <%residualFunction%>
      <%sparseData%>
      <%bodyStaticData%>
      <%updateIterationVars%>
      /* casual tearing set */
      <%residualFunctionCasual%>
      <%sparseDataCasual%>
      <%bodyStaticDataCasual%>
      <%updateIterationVarsCasual%>
      /* end residuals for dynamic tearing sets */
      >>
    )
    ;separator="\n\n")
end functionNonLinearResiduals;

template generateNonLinearResidualFunction(NonlinearSystem system, String modelNamePrefix, Integer whichSet)
  "Generates residual function for nonlinear loops.
   whichSet = 0: Strict Set
   whichSet = 1: Casual Set"
::=
let () = tmpTickReset(0)
let &sub = buffer ""
match system
  case nls as NONLINEARSYSTEM(__) then
    let &varDecls = buffer ""
    let &innerEqns = buffer ""
    let &dummyPrototypes = buffer ""
    let innerNLSSystems = functionNonLinearResiduals(nls.eqs, modelNamePrefix, dummyPrototypes)
    let backupOutputs = match nls.eqs
      case (alg as SES_INVERSE_ALGORITHM(__))::{} then
        let body = (alg.knownOutputCrefs |> cr hasindex i0 =>
          let &varDecls += '<%crefType(cr)%> OLD_<%i0%>;<%\n%>'
          'OLD_<%i0%> = <%cref(cr, &sub)%>;'
        ;separator="\n")
        <<
        /* backup outputs of the algorithm */
        <%body%>
        >>
    let restoreKnownOutputs = match nls.eqs
      case (alg as SES_INVERSE_ALGORITHM(__))::{} then
        let body = (alg.knownOutputCrefs |> cr hasindex i0 => '<%cref(cr, &sub)%> = OLD_<%i0%>;' ;separator="\n")
        <<
        /* restore previously known outputs of the algorithm */
        <%body%>
        >>
    let xlocs = (nls.crefs |> cr hasindex i0 => '<%cref(cr, &sub)%> = xloc[<%i0%>];' ;separator="\n")
    let prebody = (nls.eqs |> eq2 =>
      functionExtraResidualsPreBody(eq2, &innerEqns, modelNamePrefix)
    ;separator="\n")
    let body = match nls.eqs
      case (alg as SES_INVERSE_ALGORITHM(__))::{} then
        let init = (nls.crefs |> cr hasindex i0 => 'res[<%i0%>] = 0;' ;separator="\n")
        let known = (alg.knownOutputCrefs |> cr hasindex i0 => 'res[(int)fmod(<%i0%>, <%listLength(nls.crefs)%>)] += pow(OLD_<%i0%> - <%cref(cr, &sub)%>, 2);' ;separator="\n")
        <<
        <%init%>
        <%known%>
        >>
      else
        (nls.eqs |> eq2 hasindex i0 => match eq2
          case SES_RESIDUAL(__) then
            let &preExp = buffer ""
            let expPart = daeExp(exp, contextSimulationDiscrete, &preExp, &varDecls, &innerEqns)
            <<
            <% if profileAll() then 'SIM_PROF_TICK_EQ(<%index%>);' %>
            <%preExp%>res[<%res_index%>] = <%expPart%>;
            <% if profileAll() then 'SIM_PROF_ACC_EQ(<%index%>);' %>
            >>
          case SES_FOR_RESIDUAL(__) then
            let &preExp = buffer ""
            let expPart = daeExp(exp, contextSimulationDiscrete, &preExp, &varDecls, &innerEqns)
            let forPart = (iterators |> iterator => match iterator
                case (cref, range as DAE.RANGE()) then
                  let iter = daeExp(crefExp(cref), contextSimulationDiscrete, &preExp, &varDecls, &innerEqns)
                  let start = daeExp(range.start, contextSimulationDiscrete, &preExp, &varDecls, &innerEqns)
                  let stop = daeExp(range.stop, contextSimulationDiscrete, &preExp, &varDecls, &innerEqns)
                  let step = match range.step case SOME(step) then daeExp(step, contextSimulationDiscrete, &preExp, &varDecls, &innerEqns) else "1"
                  <<for(int <%iter%>=<%start%>; <%iter%><=<%stop%>; <%iter%>+=<%step%>){>>
                ;separator="\n")
            let endForPart = (iterators |> iterator => "}")
            let indexShift = (iterators |> iterator => match iterator
                case (cref, range as DAE.RANGE()) then
                  let start = daeExp(range.start, contextSimulationDiscrete, &preExp, &varDecls, &innerEqns)
                  '<%daeExp(crefExp(cref), contextSimulationDiscrete, &preExp, &varDecls, &innerEqns)%>-<%start%>'
                ;separator="+")
            <<
            <% if profileAll() then 'SIM_PROF_TICK_EQ(<%index%>);' %>
            <%forPart%>
            <%preExp%>res[<%res_index%>+<%indexShift%>] = <%expPart%>;
            <%endForPart%>
            <% if profileAll() then 'SIM_PROF_ACC_EQ(<%index%>);' %>
            >>
          case SES_GENERIC_RESIDUAL(__) then
            let &preExp = buffer ""
            let idx_len = listLength(scal_indices)
            let expPart = daeExp(exp, contextSimulationDiscrete, &preExp, &varDecls, &innerEqns)
            let iter_ = (iterators |> iterator => match iterator
                case (cref, range as DAE.RANGE()) then
                let iter = daeExp(crefExp(cref), contextSimulationDiscrete, &preExp, &varDecls, &innerEqns)
                let start = daeExp(range.start, contextSimulationDiscrete, &preExp, &varDecls, &innerEqns)
                let stop = daeExp(range.stop, contextSimulationDiscrete, &preExp, &varDecls, &innerEqns)
                let step = match range.step case SOME(step) then daeExp(step, contextSimulationDiscrete, &preExp, &varDecls, &innerEqns) else "1"
                <<
                const int <%iter%>_size = <%stop%> - <%start%> / <%step%> + 1;
                int <%iter%>_loc = tmp % <%iter%>_size;
                int <%iter%> = <%step%> * <%iter%>_loc + <%start%>;
                tmp /= <%iter%>_size;
                >>;separator="\n")
            <<
            const int idx_lst[<%idx_len%>] = {<%(scal_indices |> idx => '<%idx%>';separator=", ")%>};
            for(int i_=0; i_<<%idx_len%>; i_++)
            {
              int tmp = idx_lst[i_];
              <%iter_%>
              <%preExp%>res[<%res_index%>+i_] = <%expPart%>;
            }
            >>
        ;separator="\n")
    let residualFunctionHeader =
      if intEq(whichSet, 0) then
        'void residualFunc<%nls.index%>(RESIDUAL_USERDATA* userData, const double* xloc, double* res, const int* iflag)'
      else
        'int residualFuncConstraints<%nls.index%>(RESIDUAL_USERDATA* userData, const double* xloc, double* res, const int* iflag)'
    let returnValue = if intEq(whichSet, 1) then 'return 0;'
    <<
    <%innerNLSSystems%>

    /* inner equations */
    <%&innerEqns%>

    <%residualFunctionHeader%>
    {
      TRACE_PUSH
      DATA *data = userData->data;
      threadData_t *threadData = userData->threadData;
      const int equationIndexes[2] = {1,<%nls.index%>};
      int i,j;<% if clockIndex then <<
      const int clockIndex = <%clockIndex%>;
      >> %>
      <%varDecls%>
      <% if profileAll() then 'SIM_PROF_TICK_EQ(<%nls.index%>);' %>
      <% if profileSome() then 'SIM_PROF_ADD_NCALL_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%nls.index%>).profileBlockIndex,1);' %>
      /* iteration variables */
      for (i=0; i<<%listLength(nls.crefs)%>; i++) {
        if (isinf(xloc[i]) || isnan(xloc[i])) {
          errorStreamPrint(LOG_NLS, 0, "residualFunc<%nls.index%>: Iteration variable xloc[%i] is nan.", i);
          for (j=0; j<<%listLength(nls.crefs)%>; j++) {
            res[j] = NAN;
          }
          throwStreamPrintWithEquationIndexes(threadData, omc_dummyFileInfo, equationIndexes, "residualFunc<%nls.index%> failed at time=%.15g.\nFor more information please use -lv LOG_NLS.", data->localData[0]->timeValue);
          <%if intEq(whichSet, 0) then "return;" else "return 1;"%>
        }
      }
      <%xlocs%>
      /* backup outputs */
      <%backupOutputs%>
      /* pre body */
      <%prebody%>
      /* body */
      <%body%>
      /* restore known outputs */
      <%restoreKnownOutputs%>
      <% if profileAll() then 'SIM_PROF_ACC_EQ(<%nls.index%>);' %>
      TRACE_POP
      <%returnValue%>
    }
    >>
end generateNonLinearResidualFunction;

template generateStaticEmptySparseData(String indexName, String systemType)
"template generateStaticEmptySparseData
  This template generates source code for functions that initialize the sparse-pattern."
::=
  <<
  void initializeSparsePattern<%indexName%>(<%systemType%>* inSysData)
  {
    /* no sparsity pattern available */
    inSysData->isPatternAvailable = FALSE;
  }

  void freeSparsePattern<%indexName%>(<%systemType%>* inSysData)
  {
    /* nothing to free */
  }
  >>
end generateStaticEmptySparseData;

template generateStaticSparseData(String indexName, String systemType, SparsityPattern sparsepattern, list<list<Integer>> colorList, Integer maxColor)
"template generateStaticSparseData
  This template generates source code for functions that initialize the sparse-pattern."
::=
  match sparsepattern
  case {} then
     let emptySparse = generateStaticEmptySparseData(indexName, systemType)
     <<
     <%emptySparse%>
     >>
  case _ then
      let sp_size_index = lengthListElements(unzipSecond(sparsepattern))
      let sizeleadindex = listLength(sparsepattern)
      let colPtr = genSPCRSPtr(listLength(sparsepattern), sparsepattern, "colPtrIndex")
      let rowIndex = genSPCRSRows(lengthListElements(unzipSecond(sparsepattern)), sparsepattern, "rowIndex")
      let colorString = genSPColors(colorList, "inSysData->sparsePattern->colorCols")
      <<

      OMC_DISABLE_OPT
      void initializeSparsePattern<%indexName%>(<%systemType%>* inSysData)
      {
        int i=0;
        <%colPtr%>
        <%rowIndex%>
        /* sparsity pattern available */
        inSysData->isPatternAvailable = TRUE;
        inSysData->sparsePattern = allocSparsePattern(<%sizeleadindex%>, <%sp_size_index%>, <%maxColor%>);

        /* write lead index of compressed sparse column */
        memcpy(inSysData->sparsePattern->leadindex, colPtrIndex, (<%sizeleadindex%>+1)*sizeof(unsigned int));

        for(i=2;i<<%sizeleadindex%>+1;++i)
          inSysData->sparsePattern->leadindex[i] += inSysData->sparsePattern->leadindex[i-1];

        /* call sparse index */
        memcpy(inSysData->sparsePattern->index, rowIndex, <%sp_size_index%>*sizeof(unsigned int));

        /* write color array */
        <%colorString%>
      }

      void freeSparsePattern<%indexName%>(<%systemType%>* inSysData)
      {
        if (inSysData->isPatternAvailable) {
          freeSparsePattern(inSysData->sparsePattern);
          free(inSysData->sparsePattern);
          inSysData->sparsePattern = NULL;
          inSysData->isPatternAvailable = FALSE;
        }
      }
      >>
   end match
end generateStaticSparseData;

template generateStaticEmptyNonlinearData(String indexName, String systemType)
"template generateStaticEmptyNonlinearData
  This template generates source code for functions that initialize the nonlinear-pattern."
::=
  <<
  void initializeNonlinearPattern<%indexName%>(<%systemType%>* inSysData)
  {
    /* no nonlinear pattern available */
  }
  >>
end generateStaticEmptyNonlinearData;

template generateStaticNonlinearData(String indexName, String systemType, NonlinearPattern nonlinearpattern, NonlinearPattern nonlinearpatternT)
"template generateStaticNonlinearData
  This template generates source code for functions that initialize the nonlinear-pattern."
::=
  match nonlinearpattern
  case {} then
      <<
      void initializeNonlinearPattern<%indexName%>(<%systemType%>* inSysData)
      {
        /* no nonlinear pattern available */
      }
      >>
  case _ then
      let number_vars = listLength(nonlinearpatternT)
      let number_eqns = listLength(nonlinearpattern)
      let number_nonlinear = lengthListElements(unzipSecond(nonlinearpattern))
      let index_var = genSPCRSPtr(listLength(nonlinearpatternT), nonlinearpatternT, "index_var")
      let index_eqn = genSPCRSPtr(listLength(nonlinearpatternT), nonlinearpatternT, "index_eqn")
      let columns = genSPCRSRows(lengthListElements(unzipSecond(nonlinearpatternT)), nonlinearpatternT, "columns")
      let rows = genSPCRSRows(lengthListElements(unzipSecond(nonlinearpattern)), nonlinearpattern, "rows")
      <<
      OMC_DISABLE_OPT
      void initializeNonlinearPattern<%indexName%>(<%systemType%>* inSysData)
      {
        int i=0;
        inSysData->nonlinearPattern = (NONLINEAR_PATTERN*) malloc(sizeof(NONLINEAR_PATTERN));
        inSysData->nonlinearPattern->numberOfVars = <%number_vars%>;
        inSysData->nonlinearPattern->numberOfEqns = <%number_eqns%>;
        inSysData->nonlinearPattern->numberOfNonlinear = <%number_nonlinear%>;
        inSysData->nonlinearPattern->indexVar = (unsigned int*) malloc((<%number_vars%>+1)*sizeof(unsigned int));
        inSysData->nonlinearPattern->indexEqn = (unsigned int*) malloc((<%number_eqns%>+1)*sizeof(unsigned int));
        inSysData->nonlinearPattern->columns = (unsigned int*) malloc(<%number_nonlinear%>*sizeof(unsigned int));
        inSysData->nonlinearPattern->rows = (unsigned int*) malloc(<%number_nonlinear%>*sizeof(unsigned int));
        /* initialize and accumulate index vectors */
        <%index_var%>
        <%index_eqn%>
        memcpy(inSysData->nonlinearPattern->indexVar, index_var, (<%number_vars%>+1)*sizeof(unsigned int));
        memcpy(inSysData->nonlinearPattern->indexEqn, index_eqn, (<%number_eqns%>+1)*sizeof(unsigned int));
        for(i=2;i<<%number_vars%>+1;++i)
          inSysData->nonlinearPattern->indexVar[i] += inSysData->nonlinearPattern->indexVar[i-1];
        for(i=2;i<<%number_eqns%>+1;++i)
          inSysData->nonlinearPattern->indexEqn[i] += inSysData->nonlinearPattern->indexEqn[i-1];
        /* initialize columns and rows */
        <%columns%>
        <%rows%>
        memcpy(inSysData->nonlinearPattern->columns, columns, <%number_nonlinear%>*sizeof(unsigned int));
        memcpy(inSysData->nonlinearPattern->rows, rows, <%number_nonlinear%>*sizeof(unsigned int));
      }
      >>
   end match
end generateStaticNonlinearData;

template generateStaticInitialData(list<ComponentRef> crefs, String indexName)
  "Generates initial function for nonlinear loops."
::=
  let systemType = 'NONLINEAR_SYSTEM_DATA'
  let bodyStaticData = (crefs |> cr hasindex i0 =>
    <<
    /* static nls data for <%crefStrNoUnderscore(cr)%> */
    sysData->nominal[i] = <%crefAttributes(cr)%>.nominal;
    sysData->min[i]     = <%crefAttributes(cr)%>.min;
    sysData->max[i++]   = <%crefAttributes(cr)%>.max;
    >>
  ;separator="\n")
  <<

  OMC_DISABLE_OPT
  void initializeStaticData<%indexName%>(DATA* data, threadData_t *threadData, NONLINEAR_SYSTEM_DATA *sysData, modelica_boolean initSparsePattern, modelica_boolean initNonlinearPattern)
  {
    int i=0;
    <%bodyStaticData%>
    /* initial sparse pattern */
    if (initSparsePattern) {
      initializeSparsePattern<%indexName%>(sysData);
    }
    if (initNonlinearPattern) {
      initializeNonlinearPattern<%indexName%>(sysData);
    }
  }

  OMC_DISABLE_OPT
  void freeStaticData<%indexName%>(DATA* data, threadData_t *threadData, NONLINEAR_SYSTEM_DATA *sysData)
  {
    freeSparsePattern<%indexName%>(sysData);
  }
  >>
end generateStaticInitialData;

template getIterationVars(list<ComponentRef> crefs, String indexName)
  "Generates iteration variables update."
::=
  let &sub = buffer ""
  let vars = (crefs |> cr hasindex i0 =>
      'array[<%i0%>] = <%cref(cr, &sub)%>;'
  ;separator="\n")
  <<

  OMC_DISABLE_OPT
  void getIterationVars<%indexName%>(DATA* data, double *array)
  {
    <%vars%>
  }
  >>
end getIterationVars;

// =============================================================================
// section for State Sets
//
// This section generates the followng c functions:
//   - void initializeStateSets(int nStateSets, STATE_SET_DATA* statesetData, DATA *data)
// =============================================================================

template functionInitialStateSets(SimCode simCode, list<StateSet> stateSets, String modelNamePrefix)
  "Generates functions in simulation file to initialize the stateset data."
::=
     let body = (stateSets |> set hasindex i1 fromindex 0 => (match set
       case set as SES_STATESET(__) then
       let generatedJac = match jacobianMatrix case JAC_MATRIX(matrixName=name) then '<%symbolName(modelNamePrefix,"functionJac")%><%name%>_column'
       let initialJac =  match jacobianMatrix case JAC_MATRIX(matrixName=name) then '<%symbolName(modelNamePrefix,"initialAnalyticJacobian")%><%name%>'
       let jacIndex = match jacobianMatrix case JAC_MATRIX(jacobianIndex=jacindex) then '<%jacindex%>'
       let statesvars = (states |> s hasindex i2 fromindex 0 => 'statesetData[<%i1%>].states[<%i2%>] = &<%crefVarInfo( s)%>;' ;separator="\n")
       let statescandidatesvars = (statescandidates |> cstate hasindex i2 fromindex 0 => 'statesetData[<%i1%>].statescandidates[<%i2%>] = &<%crefVarInfo( cstate)%>;' ;separator="\n")
       <<
       assertStreamPrint(NULL, nStateSets > <%i1%>, "Internal Error: nStateSets mismatch!");
       statesetData[<%i1%>].nCandidates = <%nCandidates%>;
       statesetData[<%i1%>].nStates = <%nStates%>;
       statesetData[<%i1%>].nDummyStates = <%nCandidates%>-<%nStates%>;
       statesetData[<%i1%>].states = (VAR_INFO**) calloc(<%nStates%>,sizeof(VAR_INFO));
       <%statesvars%>
       statesetData[<%i1%>].statescandidates = (VAR_INFO**) calloc(<%nCandidates%>,sizeof(VAR_INFO));
       <%statescandidatesvars%>
       statesetData[<%i1%>].A = &<%crefVarInfo( crA)%>;
       statesetData[<%i1%>].rowPivot = (modelica_integer*) calloc(<%nCandidates%>-<%nStates%>,sizeof(modelica_integer));
       statesetData[<%i1%>].colPivot = (modelica_integer*) calloc(<%nCandidates%>,sizeof(modelica_integer));
       statesetData[<%i1%>].J = (modelica_real*) calloc(<%nCandidates%>*(<%nCandidates%>-<%nStates%>),sizeof(modelica_real));
       statesetData[<%i1%>].analyticalJacobianColumn = <%generatedJac%>;
       statesetData[<%i1%>].initialAnalyticalJacobian = <%initialJac%>;
       statesetData[<%i1%>].jacobianIndex = <%jacIndex%>;

       >>
   )
   ;separator="\n\n")
  <<
  /* funtion initialize state sets */
  void <%symbolName(modelNamePrefix,"initializeStateSets")%>(int nStateSets, STATE_SET_DATA* statesetData, DATA *data)
  {
    <%body%>
  }
  >>
end functionInitialStateSets;

// =============================================================================
// section for initialization
//
// This section generates the followng c functions:
//   - int updateBoundParameters(DATA *data)
//   - int updateBoundVariableAttributes(DATA *data)
//   - int functionInitialEquations(DATA *data)
//   - int functionInitialEquations_lambda0(DATA *data)
//   - int functionRemovedInitialEquations(DATA *data)
// =============================================================================

template functionUpdateBoundVariableAttributes(SimCode simCode, list<SimEqSystem> startValueEquations, list<SimEqSystem> nominalValueEquations, list<SimEqSystem> minValueEquations, list<SimEqSystem> maxValueEquations, String modelNamePrefix)
  "Generates function in simulation file."
::=
let &sub = buffer ""
  <<
  <%(startValueEquations |> eq as SES_SIMPLE_ASSIGN(__) => equation_impl2(-1, -1, eq, contextOther, modelNamePrefix, /* Static? */ true, /* No optimization */ false, /* Initial? */ true) ; separator="\n")%>
  <%(nominalValueEquations |> eq as SES_SIMPLE_ASSIGN(__) => functionUpdateBoundVariableAttributesFunctions(eq, "nominal", contextOther, modelNamePrefix, /* Static? */ true, /* No optimization */ false) ; separator="\n") %>
  <%(minValueEquations |> eq as SES_SIMPLE_ASSIGN(__) => functionUpdateBoundVariableAttributesFunctions(eq, "min", contextOther, modelNamePrefix, /* Static? */ true, /* No optimization */ false) ; separator="\n") %>
  <%(maxValueEquations |> eq as SES_SIMPLE_ASSIGN(__) => functionUpdateBoundVariableAttributesFunctions(eq, "max", contextOther, modelNamePrefix, /* Static? */ true, /* No optimization */ false) ; separator="\n") %>
  OMC_DISABLE_OPT
  int <%symbolName(modelNamePrefix,"updateBoundVariableAttributes")%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH
    /* min ******************************************************** */
    infoStreamPrint(LOG_INIT, 1, "updating min-values");
    <%minValueEquations |> eq as SES_SIMPLE_ASSIGN(__) => equation_call(eq, modelNamePrefix)%>
    if (ACTIVE_STREAM(LOG_INIT)) messageClose(LOG_INIT);

    /* max ******************************************************** */
    infoStreamPrint(LOG_INIT, 1, "updating max-values");
    <%maxValueEquations |> eq as SES_SIMPLE_ASSIGN(__) => equation_call(eq, modelNamePrefix)%>
    if (ACTIVE_STREAM(LOG_INIT)) messageClose(LOG_INIT);

    /* nominal **************************************************** */
    infoStreamPrint(LOG_INIT, 1, "updating nominal-values");
    <%nominalValueEquations |> eq as SES_SIMPLE_ASSIGN(__) => equation_call(eq, modelNamePrefix)%>
    if (ACTIVE_STREAM(LOG_INIT)) messageClose(LOG_INIT);

    /* start ****************************************************** */
    infoStreamPrint(LOG_INIT, 1, "updating primary start-values");
    <%(startValueEquations |> eq as SES_SIMPLE_ASSIGN(__) => equation_call(eq, modelNamePrefix) ; separator="\n")%>
    if (ACTIVE_STREAM(LOG_INIT)) messageClose(LOG_INIT);

    TRACE_POP
    return 0;
  }
  >>
end functionUpdateBoundVariableAttributes;

template functionUpdateBoundVariableAttributesFunctions(SimEqSystem eq, String attribute, Context context, String modelNamePrefix, Boolean static, Boolean noOpt)
 "Generates an a function representing an equation for an attribute binding (e.g min, max ...)"
::=
  let OMC_NO_OPT = if noOpt then 'OMC_DISABLE_OPT<%\n%>' else (match eq case SES_LINEAR(__) then 'OMC_DISABLE_OPT<%\n%>')
  match eq
    case SES_SIMPLE_ASSIGN(exp=CALL(path=IDENT(name="fail")))
    case SES_SIMPLE_ASSIGN_CONSTRAINTS(exp=CALL(path=IDENT(name="fail"))) then
      '<%generateThrow()%><%\n%>'

    case SES_SIMPLE_ASSIGN(__)
    case SES_SIMPLE_ASSIGN_CONSTRAINTS(__) then

      let ix = equationIndex(eq) /*System.tmpTickIndex(10)*/
      let &varDecls = buffer ""
      let &auxFunction = buffer ""
      let body = functionUpdateBoundVariableAttributesFunctionsSimpleAssign(eq, attribute, context, &varDecls, &auxFunction)

      <<
      /*
      <%dumpEqs(fill(eq,1))%>
      */
      <%OMC_NO_OPT%><% if static then "static "%>void <%symbolName(modelNamePrefix,"eqFunction")%>_<%ix%>(DATA *data, threadData_t *threadData)
      {
        TRACE_PUSH
        const int equationIndexes[2] = {1,<%ix%>};
        <%&varDecls%>
        <%body%>
        TRACE_POP
      }

      >>

    else "NOT IMPLEMENTED EQUATION equation_"
end functionUpdateBoundVariableAttributesFunctions;

template functionUpdateBoundVariableAttributesFunctionsSimpleAssign(SimEqSystem eq, String attribute, Context context,
                              Text &varDecls, Text &auxFunction)
 "Generates an equation that is just a simple assignment for an arribute binding. The attribute type is given by the
 function argument 'attibute' (e.g min, max ...)"
::=
match eq
case SES_SIMPLE_ASSIGN(__)
case SES_SIMPLE_ASSIGN_CONSTRAINTS(__) then
  let &sub = buffer ""
  let &preExp = buffer ""
  let expPart = daeExp(exp, context, &preExp, &varDecls, &auxFunction)
  let postExp = if isStartCref(cref) then
    <<
    <%cref(popCref(cref), &sub)%> = <%cref(cref, &sub)%>;
    infoStreamPrint(LOG_INIT_V, 0, "updated start value: %s(start=<%crefToPrintfArg(popCref(cref))%>)", <%crefVarInfo(popCref(cref))%>.name, (<%crefType(popCref(cref))%>) <%cref(popCref(cref), &sub)%>);
    >>
  <<
  <%modelicaLine(eqInfo(eq))%>
  <%preExp%>
  <%crefAttributes(cref)%>.<%attribute%> = <%expPart%>;
  infoStreamPrint(LOG_INIT_V, 0, "%s(<%attribute%>=<%crefToPrintfArg(cref)%>)", <%crefVarInfo(cref)%>.name,
        (<%crefType(cref)%>) <%crefAttributes(cref)%>.<%attribute%>);
  <%postExp%>
  <%endModelicaLine()%>
  >>
end functionUpdateBoundVariableAttributesFunctionsSimpleAssign;


template functionUpdateBoundParameters(list<SimEqSystem> simpleParameterEquations, list<SimEqSystem> parameterEquations, String fileNamePrefix, String fullPathPrefix, String modelNamePrefix, SimCode simCode)
  "Generates function in simulation file."
::=
  let &sub = buffer ""
  let &eqFuncs = buffer ""
  let &auxFunction = buffer ""
  let fncalls = functionEquationsMultiFiles(parameterEquations, listLength(parameterEquations),
    Flags.getConfigInt(Flags.EQUATIONS_PER_FILE), fileNamePrefix, fullPathPrefix, modelNamePrefix,
    "updateBoundParameters", "08bnd", &eqFuncs, /* Static? */ true, true /* No optimization */, /* initial? */ false)
  <<
  <%eqFuncs%>
  OMC_DISABLE_OPT
  int <%symbolName(modelNamePrefix,"updateBoundParameters")%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH
    <%sortSimpleAssignmentBasedOnLhs(simpleParameterEquations) |> eq as SES_SIMPLE_ASSIGN(__) =>
      <<
      <%cref(cref, &sub)%> = <%daeExpSimpleLiteral(exp)%>;
      <%match cref2simvar(cref, simCode)
        case SIMVAR(aliasvar=NOALIAS(), varKind=PARAM()) then
          'data->modelData-><%expTypeShort(type_)%>ParameterData[<%index%>].time_unvarying = 1;'
        case SIMVAR(aliasvar=NOALIAS()) then
          'data->modelData-><%expTypeShort(type_)%>VarsData[<%index%>].time_unvarying = 1;'
        else error(sourceInfo(), 'Cannot get attributes of alias variable <%crefStr(cref)%>. Alias variables should have been replaced by the compiler before SimCode')%>
      >> ; separator="\n" %>
    <%fncalls%>
    TRACE_POP
    return 0;
  }
  >>
end functionUpdateBoundParameters;

template functionEquationsMultiFiles(list<SimEqSystem> inEqs, Integer numEqs, Integer equationsPerFile, String fileNamePrefix, String fullPathPrefix, String modelNamePrefix, String funcName, String partName, Text &eqFuncs, Boolean static, Boolean noOpt, Boolean init)
::=
  let () = System.tmpTickReset(0)
  let &file = buffer ""
  let multiFile = if intGt(numEqs, equationsPerFile) then "x"
  let fncalls = (List.balancedPartition(inEqs, equationsPerFile) |> eqs hasindex i0 =>
                  let name = symbolName(modelNamePrefix,'<%funcName%>_<%i0%>')
                  let &eqFuncs += 'void <%name%>(DATA *data, threadData_t *threadData);<%\n%>'

                  // To file
                  let &file += ((if multiFile then
                    (let fileName = addFunctionIndex('<%fileNamePrefix%>_<%partName%>_part', ".c")
                    redirectToFile(fullPathPrefix + fileName) +
                  <<
                  <%simulationFileHeader(fileNamePrefix)%>
                  #if defined(__cplusplus)
                  extern "C" {
                  #endif<%\n%>
                  >>)) +
                  (eqs |> eq => equation_impl_options(-1, -1, eq, contextSimulationDiscrete, modelNamePrefix, static, noOpt, init) ; separator="\n") +
                  <<
                  <%\n%>
                  OMC_DISABLE_OPT
                  void <%name%>(DATA *data, threadData_t *threadData)
                  {
                    TRACE_PUSH
                    <%eqs |> eq => equation_call(eq, modelNamePrefix) %>
                    TRACE_POP
                  }
                  >>
                  +
                  (if multiFile then
                  (<<

                  #if defined(__cplusplus)
                  }
                  #endif
                  >> +
                  closeFile())))

                   // fncalls
                  '<%name%>(data, threadData);<%\n%>'

                  )

  let &eqFuncs += file
  fncalls
end functionEquationsMultiFiles;

template functionInitialEquations(list<SimEqSystem> initalEquations, Integer numInitialEquations, String fileNamePrefix, String fullPathPrefix, String modelNamePrefix, Boolean init)
  "Generates function in simulation file."
::=
  let () = System.tmpTickReset(0)
  let &eqfuncs = buffer ""
  let fncalls = functionEquationsMultiFiles(initalEquations, numInitialEquations, Flags.getConfigInt(Flags.EQUATIONS_PER_FILE),
                  fileNamePrefix, fullPathPrefix, modelNamePrefix, "functionInitialEquations", "06inz", &eqfuncs, /* not static */ false,
                  /* do optimize */ false, /* initial */ init)

  <<
  <%eqfuncs%>

  int <%symbolName(modelNamePrefix,"functionInitialEquations")%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH

    data->simulationInfo->discreteCall = 1;
    <%fncalls %>
    data->simulationInfo->discreteCall = 0;

    TRACE_POP
    return 0;
  }
  >>
end functionInitialEquations;

template functionInitialEquations_lambda0(list<SimEqSystem> initalEquations_lambda0, String modelNamePrefix)
  "Generates function in simulation file."
::=
  match initalEquations_lambda0
  case {} then
    <<

    /* No <%symbolName(modelNamePrefix,"functionInitialEquations_lambda0")%> function */

    >>
  else
    let () = System.tmpTickReset(0)
    let nrfuncs = listLength(initalEquations_lambda0)
    let &eqfuncs = buffer ""
    let fncalls =
                let &eqfuncs += (initalEquations_lambda0 |> eq hasindex i0 => equation_impl(-1, -1, eq, contextSimulationDiscrete,
                    modelNamePrefix, true) ;separator="\n")
                (initalEquations_lambda0 |> eq hasindex i0 => equation_call(eq, modelNamePrefix) ;separator="\n")
    <<
    <%eqfuncs%>

    int <%symbolName(modelNamePrefix,"functionInitialEquations_lambda0")%>(DATA *data, threadData_t *threadData)
    {
      TRACE_PUSH

      data->simulationInfo->discreteCall = 1;
      <%fncalls %>
      data->simulationInfo->discreteCall = 0;

      TRACE_POP
      return 0;
    }
    >>
  end match
end functionInitialEquations_lambda0;

template functionRemovedInitialEquationsBody(SimEqSystem eq, Text &varDecls, Text &eqs, String modelNamePrefix)
 "Generates an equation."
::=
  match eq
  case e as SES_RESIDUAL(__) then
    match exp
    case DAE.SCONST(__) then
      'res = 0;'
    else
      let &preExp = buffer ""
      let expPart = daeExp(exp, contextOther, &preExp, &varDecls, &eqs)
      <<
      <% if profileAll() then 'SIM_PROF_TICK_EQ(<%e.index%>);' %>
      <%preExp%>res = <%expPart%>;
      <% if profileAll() then 'SIM_PROF_ACC_EQ(<%e.index%>);' %>
      if(fabs(res) > 1e-5)
      {
        errorStreamPrint(LOG_INIT, 0, "The initialization problem is inconsistent due to the following equation: 0 != %g = <%dumpExp(exp,"\"")%>", res);
        return 1;
      }
      >>
    end match
  case SES_FOR_RESIDUAL(__) then "case 8"
  else
    let &eqs += equation_impl(-1, -1, eq, contextSimulationDiscrete, modelNamePrefix, true)
    equation_call(eq, modelNamePrefix)
  end match
end functionRemovedInitialEquationsBody;

template functionRemovedInitialEquations(list<SimEqSystem> removedInitalEquations, String modelNamePrefix)
  "Generates function in simulation file."
::=
  let &varDecls = buffer ""
  let &tmp = buffer ""

  let body = (removedInitalEquations |> eq2 =>
       functionRemovedInitialEquationsBody(eq2, &varDecls, &tmp, modelNamePrefix)
     ;separator="\n")

  <<
  <%tmp%>
  int <%symbolName(modelNamePrefix,"functionRemovedInitialEquations")%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH
    const int *equationIndexes = NULL;
    double res = 0.0;
    <%varDecls%>

    <%body%>

    TRACE_POP
    return 0;
  }
  >>
end functionRemovedInitialEquations;

template functionStoreDelayed(DelayedExpression delayed, String modelNamePrefix)
  "Generates function in simulation file."
::=
  let &varDecls = buffer ""
  let &auxFunction = buffer ""
  let storePart = (match delayed case DELAYED_EXPRESSIONS(__) then (delayedExps |> (id, (e, d, delayMax)) =>
      let &preExp = buffer ""
      let eRes = daeExp(e, contextSimulationNonDiscrete, &preExp, &varDecls, &auxFunction)
      let delayExp = daeExp(d, contextSimulationNonDiscrete, &preExp, &varDecls, &auxFunction)
      let delayExpMax = daeExp(delayMax, contextSimulationNonDiscrete, &preExp, &varDecls, &auxFunction)
      <<
      equationIndexes[1] = <%id%>;
      <%preExp%>
      storeDelayedExpression(data, threadData, <%id%>, <%eRes%>, <%delayExp%>, <%delayExpMax%>);<%\n%>
      >>
    ))
  <<
  <%auxFunction%>
  int <%symbolName(modelNamePrefix,"function_storeDelayed")%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH

    int equationIndexes[2] = {1,-1};
    <%varDecls%>
    <%storePart%>

    TRACE_POP
    return 0;
  }
  >>
end functionStoreDelayed;

template functionStoreSpatialDistribution(SpatialDistributionInfo spatialInfo, String modelNamePrefix)
  "Generates function in simulation file."
::=
  let &varDecls = buffer ""
  let &auxFunction = buffer ""
  let storePart = (match spatialInfo case SPATIAL_DISTRIBUTION_INFO(__) then (spatialDistributions |> SPATIAL_DISTRIBUTION(index=index, in0=in0, in1=in1, pos=pos, dir=dir) =>
      let &preExp = buffer ""
      let in0T = daeExp(in0, contextSimulationNonDiscrete, &preExp, &varDecls, &auxFunction)
      let in1T = daeExp(in1, contextSimulationNonDiscrete, &preExp, &varDecls, &auxFunction)
      let posT = daeExp(pos, contextSimulationNonDiscrete, &preExp, &varDecls, &auxFunction)
      let dirT = daeExp(dir, contextSimulationNonDiscrete, &preExp, &varDecls, &auxFunction)
      // TODO @kabdelhak Use index of equation here, not the index of the spatial distribution
      <<
      equationIndexes[1] = <%index%>;
      <%preExp%>
      storeSpatialDistribution(data, threadData, <%index%>, <%in0T%>, <%in1T%>, <%posT%>, <%dirT%>);<%\n%>
      >>
    ))
  <<
  <%auxFunction%>
  int <%symbolName(modelNamePrefix,"function_storeSpatialDistribution")%>(DATA *data, threadData_t *threadData)
  {
    int equationIndexes[2] = {1,-1};
    <%varDecls%>
    <%storePart%>

    TRACE_POP
    return 0;
  }
  >>
end functionStoreSpatialDistribution;

template functionInitSpatialDistribution(SpatialDistributionInfo spatialInfo, String modelNamePrefix)
  "Generates function in simulation file."
::=
  let &varDecls = buffer ""
  let &auxFunction = buffer ""
  let storePart = (match spatialInfo case SPATIAL_DISTRIBUTION_INFO(__) then (spatialDistributions |> SPATIAL_DISTRIBUTION(index=index, initPnts=initPnts, initVals=initVals, initSize=initSize) =>
      let &preExp = buffer ""
      let initPntsT = daeExp(initPnts, contextSimulationNonDiscrete, &preExp, &varDecls, &auxFunction)
      let initValsT = daeExp(initVals, contextSimulationNonDiscrete, &preExp, &varDecls, &auxFunction)
      <<
      <%preExp%>
      initSpatialDistribution(data, threadData, <%index%>, &<%initPntsT%>, &<%initValsT%>, <%initSize%>);<%\n%>
      >>
    ))
  <<
  <%auxFunction%>
  int <%symbolName(modelNamePrefix,"function_initSpatialDistribution")%>(DATA *data, threadData_t *threadData)
  {

    <%varDecls%>
    <%storePart%>

    TRACE_POP
    return 0;
  }
  >>
end functionInitSpatialDistribution;

//------------------------------------
// Begin: Modified functions for HpcOm
//------------------------------------

template functionXXX_systems_HPCOM(list<list<SimEqSystem>> eqs, String name, Text &loop, Text &varDecls, Option<tuple<Schedule,Schedule,Schedule>> hpcOmSchedulesOpt, String modelNamePrefixStr)
::=
 let funcs = (eqs |> eq hasindex i0 fromindex 0 => functionXXX_system_HPCOM(eq,name,i0,hpcOmSchedulesOpt, modelNamePrefixStr) ; separator="\n")
 match listLength(eqs)
     case 0 then //empty case
       let &loop +=
           <<
           /* no <%name%> systems */
           >>
       <<
       void terminateHpcOmThreads()
       {

       }
       >>
     case 1 then //1 function
       let &loop +=
           <<
           function<%name%>_system0(data, threadData);
           >>
       funcs //just the one function
     case nFuncs then //2 and more
       let funcNames = eqs |> e hasindex i0 fromindex 0 => 'function<%name%>_system<%i0%>' ; separator=",\n"
       let &varDecls += 'int id;<%\n%>'
       let &loop +=
         <<
         for(id=0; id<<%nFuncs%>; id++) {
           function<%name%>_systems[id](data, threadData);
         }
         >>
       /* Text before the function head */
       <<
       <%funcs%>
       static void (*function<%name%>_systems[<%nFuncs%>])(DATA *, threadData_t *) = {
         <%funcNames%>
       };
       >>
end functionXXX_systems_HPCOM;

template functionXXX_system_HPCOM(list<SimEqSystem> derivativEquations, String name, Integer n, Option<tuple<Schedule,Schedule,Schedule>> hpcOmSchedulesOpt, String modelNamePrefixStr)
::=
  let type = getConfigString(HPCOM_CODE)
  match hpcOmSchedulesOpt
    case SOME((hpcOmSchedule as EMPTYSCHEDULE(__),_,_)) then
      <<
      void terminateHpcOmThreads()
      {
      }

      <%functionXXX_system(derivativEquations,name,n,modelNamePrefixStr)%>
      >>
    case SOME((hpcOmSchedule as TASKDEPSCHEDULE(__),_,_)) then
      let taskEqs = functionXXX_system0_HPCOM_TaskDep(hpcOmSchedule.tasks, derivativEquations, type, name, modelNamePrefixStr); separator="\n"
      <<
      void terminateHpcOmThreads()
      {
      }

      /* using type: <%type%> */
      void function<%name%>_system<%n%>(DATA *data, threadData_t *threadData)
      {
        <%taskEqs%>
      }
      >>
    case SOME((hpcOmSchedule as LEVELSCHEDULE(__),_,_)) then
      let odeEqs = hpcOmSchedule.tasksOfLevels |> tasks => functionXXX_system0_HPCOM_Level(derivativEquations,name,tasks,type,modelNamePrefixStr); separator="\n"
      <<
      void terminateHpcOmThreads()
      {
      }

      /* using type: <%type%> */
      void function<%name%>_system<%n%>(DATA *data, threadData_t *threadData)
      {
        int fail=0;
        omp_set_dynamic(0);
        #pragma omp parallel num_threads(<%getConfigInt(NUM_PROC)%>)
        {
            MMC_TRY_TOP()
            <%odeEqs%>
            MMC_CATCH_TOP(fail=1)
        }
        if (fail) {
          MMC_THROW_INTERNAL()
        }
      }
      >>
   case SOME((hpcOmSchedule as THREADSCHEDULE(__),_,_)) then
      let locks = hpcOmSchedule.outgoingDepTasks |> task => function_HPCOM_createLockByDepTask(task, "lock", type); separator="\n"
      let initlocks = hpcOmSchedule.outgoingDepTasks |> task => function_HPCOM_initializeLockByDepTask(task, "lock", type); separator="\n"
      let assignLocks = hpcOmSchedule.outgoingDepTasks |> task => function_HPCOM_assignLockByDepTask(task, "lock", type); separator="\n"
      match type
        case ("openmp") then
          let taskEqs = functionXXX_system0_HPCOM_Thread(derivativEquations,name,hpcOmSchedule.threadTasks, type, modelNamePrefixStr); separator="\n"
          <<
          void terminateHpcOmThreads()
          {
          }

          /* using type: <%type%> */
          static int initialized = 0;
          void function<%name%>_system<%n%>(DATA *data, threadData_t *threadData)
          {
            omp_set_dynamic(0);
            //create locks
            <%locks%>
            if(!initialized)
            {
                <%initlocks%>

                //set locks
                <%assignLocks%>

                initialized = 1;
            }

            <%taskEqs%>
          }
          >>
        case ("pthreads") then
          let threadDecl = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => functionXXX_system0_HPCOM_PThread_decl(i0); separator="\n"
          let threadFuncs = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => functionXXX_system0_HPCOM_PThread_func(derivativEquations, name, n, hpcOmSchedule.threadTasks, type, i0, modelNamePrefixStr); separator="\n"
          let threadFuncCalls = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => functionXXX_system0_HPCOM_PThread_call(name, n, i0); separator="\n"
          let threadStart = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => functionXXX_system0_HPCOM_PThread_start(i0); separator="\n"

          let threadLocks = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_createLockByLockName(i0, "th_lock", type); separator="\n"
          let threadLocks1 = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_createLockByLockName(i0, "th_lock1", type); separator="\n"
          let threadLocksInit = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_initializeLockByLockName(i0, "th_lock", type); separator="\n"
          let threadLocksInit1 = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_initializeLockByLockName(i0, "th_lock1", type); separator="\n"
          let threadAssignLocks = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_assignLockByLockName(i0, "th_lock", type); separator="\n"
          let threadAssignLocks1 = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_assignLockByLockName(i0, "th_lock1", type); separator="\n"
          let threadReleaseLocks = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_releaseLockByLockName(i0, "th_lock", type); separator="\n"

          <<
          // number of threads: <%arrayLength(hpcOmSchedule.threadTasks)%>
          static int finished; //set to 1 if the hpcom-threads should be destroyed

          <%threadDecl%>

          <%locks%>

          <%threadLocks%>
          <%threadLocks1%>

          void terminateHpcOmThreads()
          {
            finished = 1;

            //Start the threads one last time
            <%threadReleaseLocks%>
          }

          <%threadFuncs%>

          /* using type: <%type%> */
          static int initialized = 0;
          void function<%name%>_system<%n%>(DATA *data, threadData_t *threadData)
          {
            if(!initialized)
            {
                <%initlocks%>
                <%threadLocksInit%>
                <%threadLocksInit1%>

                //set locks
                <%assignLocks%>

                <%threadAssignLocks%>
                <%threadAssignLocks1%>

                <%threadFuncCalls%>
                initialized = 1;
            }

            //Start the threads
            <%threadReleaseLocks%>

            //"join"
            <%threadAssignLocks1%>
          }
          >>
        case ("pthreads_spin") then
          let threadDecl = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => functionXXX_system0_HPCOM_PThread_decl(i0); separator="\n"
          let threadFuncs = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => functionXXX_system0_HPCOM_PThread_func(derivativEquations, name, n, hpcOmSchedule.threadTasks, type, i0, modelNamePrefixStr); separator="\n"
          let threadFuncCalls = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => functionXXX_system0_HPCOM_PThread_call(name, n, i0); separator="\n"
          let threadStart = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => functionXXX_system0_HPCOM_PThread_start(i0); separator="\n"

          let threadLocks = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_createLockByLockName(i0, "th_lock", "pthreads"); separator="\n"
          let threadLocks1 = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_createLockByLockName(i0, "th_lock1", "pthreads"); separator="\n"
          let threadLocksInit = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_initializeLockByLockName(i0, "th_lock", "pthreads"); separator="\n"
          let threadLocksInit1 = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_initializeLockByLockName(i0, "th_lock1", "pthreads"); separator="\n"
          let threadAssignLocks = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_assignLockByLockName(i0, "th_lock", "pthreads"); separator="\n"
          let threadAssignLocks1 = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_assignLockByLockName(i0, "th_lock1", "pthreads"); separator="\n"
          let threadReleaseLocks = arrayList(hpcOmSchedule.threadTasks) |> tt hasindex i0 fromindex 0 => function_HPCOM_releaseLockByLockName(i0, "th_lock", "pthreads"); separator="\n"

          <<
          static int finished; //set to 1 if the hpcom-threads should be destroyed

          <%threadDecl%>

          <%locks%>

          <%threadLocks%>
          <%threadLocks1%>

          void terminateHpcOmThreads()
          {
            finished = 1;

            //Start the threads one last time
            <%threadReleaseLocks%>
          }

          <%threadFuncs%>

          /* using type: <%type%> */
          static int initialized = 0;
          void function<%name%>_system<%n%>(DATA *data, threadData_t *threadData)
          {
            if(!initialized)
            {
                finished = 0;

                <%initlocks%>
                <%threadLocksInit%>
                <%threadLocksInit1%>

                //set locks
                <%assignLocks%>

                <%threadAssignLocks%>
                <%threadAssignLocks1%>

                <%threadFuncCalls%>
                initialized = 1;
            }

            //Start the threads
            <%threadReleaseLocks%>

            //"join"
            <%threadAssignLocks1%>
          }
          >>

end functionXXX_system_HPCOM;

template functionXXX_system0_HPCOM_Level(list<SimEqSystem> derivativEquations, String name, TaskList tasksOfLevel, String iType, String modelNamePrefixStr)
::=
  match(tasksOfLevel)
    case(PARALLELTASKLIST(__)) then
      let odeEqs = tasks |> task => functionXXX_system0_HPCOM_Level0Section(derivativEquations,name,task,iType,modelNamePrefixStr); separator="\n"
      <<
      #pragma omp sections
      {
         <%odeEqs%>
      }
      >>
    case(SERIALTASKLIST(__)) then
      let odeEqs = tasks |> task => functionXXX_system0_HPCOM_Level0(derivativEquations,name,task,iType,modelNamePrefixStr); separator="\n"
      <<
      #pragma omp master
      {
         <%odeEqs%>
      }
      #pragma omp barrier
      >>
    else
      <<

      >>
end functionXXX_system0_HPCOM_Level;

template functionXXX_system0_HPCOM_Level0(list<SimEqSystem> derivativEquations, String name, Task iTask, String iType, String modelNamePrefixStr)
::=
  <<
    <%function_HPCOM_Task(derivativEquations,name,iTask,iType,modelNamePrefixStr)%>
  >>
end functionXXX_system0_HPCOM_Level0;

template functionXXX_system0_HPCOM_Level0Section(list<SimEqSystem> derivativEquations, String name, Task iTask, String iType, String modelNamePrefixStr)
::=
  <<
  #pragma omp section
  {
    int fail=0;
    MMC_TRY_TOP()
    <%function_HPCOM_Task(derivativEquations,name,iTask,iType,modelNamePrefixStr)%>
    MMC_CATCH_TOP(fail=1)
    if (fail) {
      MMC_THROW_INTERNAL()
    }
  }
  >>
end functionXXX_system0_HPCOM_Level0Section;

template functionXXX_system0_HPCOM_TaskDep(list<tuple<Task,list<Integer>>> tasks, list<SimEqSystem> derivativEquations, String iType, String name, String modelNamePrefixStr)
::=
  let odeEqs = tasks |> t => functionXXX_system0_HPCOM_TaskDep0(t,derivativEquations, iType, name, modelNamePrefixStr); separator="\n"
  <<

  int t[0];
  #pragma omp parallel
  {
    #pragma omp master
    {
        <%odeEqs%>
    }
  }
  >>
end functionXXX_system0_HPCOM_TaskDep;

template functionXXX_system0_HPCOM_TaskDep0(tuple<Task,list<Integer>> taskIn, list<SimEqSystem> derivativEquations, String iType, String name, String modelNamePrefixStr)
::=
  match taskIn
    case ((task as CALCTASK(__),parents)) then
        let taskEqs = function_HPCOM_Task(derivativEquations, name, task, iType, modelNamePrefixStr); separator="\n"
        let parentDependencies = parents |> p => 't[<%p%>]'; separator = ","
        let depIn = if intGt(listLength(parents),0) then 'depend(in:<%parentDependencies%>)' else ""
        <<
        #pragma omp task <%depIn%> depend(out:t[<%task.index%>])
        {
            <%taskEqs%>
        }
        >>
end functionXXX_system0_HPCOM_TaskDep0;

template functionXXX_system0_HPCOM_Thread(list<SimEqSystem> derivativEquations, String name, array<list<Task>> threadTasks, String iType, String modelNamePrefixStr)
::=
  let odeEqs = arrayList(threadTasks) |> tt => functionXXX_system0_HPCOM_Thread0(derivativEquations,name,tt,iType,modelNamePrefixStr); separator="\n"
  match iType
    case ("openmp") then
      <<
      if (omp_get_dynamic())
        omp_set_dynamic(0);
      #pragma omp parallel sections num_threads(<%arrayLength(threadTasks)%>)
      {
         <%odeEqs%>
      }
      >>
    case ("pthreads") then
      <<
      //not implemented
      >>
    case ("pthreads_spin") then
      <<
      //not implemented
      >>

end functionXXX_system0_HPCOM_Thread;

template functionXXX_system0_HPCOM_Thread0(list<SimEqSystem> derivativEquations, String name, list<Task> threadTaskList, String iType, String modelNamePrefixStr)
::=
  let threadTasks = threadTaskList |> tt => function_HPCOM_Task(derivativEquations,name,tt,iType,modelNamePrefixStr); separator="\n"
  match iType
    case ("openmp") then
      <<
      #pragma omp section
      {
        int fail=0;
        MMC_TRY_TOP()
        <%threadTasks%>
        MMC_CATCH_TOP(fail=1)
        if (fail) {
          MMC_THROW_INTERNAL()
        }
      }
      >>
    case ("pthreads") then
      <<
      <%threadTasks%>
      >>
    case ("pthreads_spin") then
      <<
      <%threadTasks%>
      >>
end functionXXX_system0_HPCOM_Thread0;

template function_HPCOM_Task(list<SimEqSystem> derivativEquations, String name, Task iTask, String iType, String modelNamePrefixStr)
::=
  match iTask
    case (task as CALCTASK(__)) then
      let odeEqs = task.eqIdc |> eq => equationNamesHPCOM_Thread_(eq,derivativEquations,contextSimulationNonDiscrete,modelNamePrefixStr); separator="\n"
      <<
      // Task <%task.index%>
      <%odeEqs%>
      // End Task <%task.index%>
      >>
    case (task as CALCTASK_LEVEL(__)) then
      let odeEqs = task.eqIdc |> eq => equationNamesHPCOM_Thread_(eq,derivativEquations,contextSimulationNonDiscrete,modelNamePrefixStr); separator="\n"
      <<
      <%odeEqs%>
      >>
    case(task as DEPTASK(outgoing=false)) then
      let assLck = function_HPCOM_assignLockByDepTask(task, "lock", iType); separator="\n"
      <<
      <%assLck%>
      >>
    case(task as DEPTASK(outgoing=true)) then
      let relLck = function_HPCOM_releaseLockByDepTask(task, "lock", iType); separator="\n"
      <<
      <%relLck%>
      >>
end function_HPCOM_Task;

template function_HPCOM_getLockNameByDepTask(Task depTask)
::=
  match(depTask)
    case(DEPTASK(sourceTask=CALCTASK(index=sourceIdx), targetTask=CALCTASK(index=targetIdx))) then
      '<%sourceIdx%>_<%targetIdx%>'
    else
      'invalidLockTask'
  end match
end function_HPCOM_getLockNameByDepTask;

template function_HPCOM_initializeLockByDepTask(Task depTask, String lockPrefix, String iType)
::=
  let lockName = function_HPCOM_getLockNameByDepTask(depTask)
  <<
  <%function_HPCOM_initializeLockByLockName(lockName, lockPrefix, iType)%>
  >>
end function_HPCOM_initializeLockByDepTask;

template function_HPCOM_initializeLockByLockName(String lockName, String lockPrefix, String iType)
::=
  match iType
    case ("openmp") then
      <<
      omp_init_lock(&<%lockPrefix%>_<%lockName%>);
      >>
    case ("pthreads") then
      <<
      pthread_mutex_init(&<%lockPrefix%>_<%lockName%>, NULL);
      >>
    case ("pthreads_spin") then
      <<
      pthread_spin_init(&<%lockPrefix%>_<%lockName%>, 0);
      >>
end function_HPCOM_initializeLockByLockName;

template function_HPCOM_createLockByDepTask(Task depTask, String lockPrefix, String iType)
::=
  let lockName = function_HPCOM_getLockNameByDepTask(depTask)
  <<
  <%function_HPCOM_createLockByLockName(lockName, lockPrefix, iType)%>
  >>
end function_HPCOM_createLockByDepTask;

template function_HPCOM_createLockByLockName(String lockName, String lockPrefix, String iType)
::=
  match iType
    case ("openmp") then
      <<
      static omp_lock_t <%lockPrefix%>_<%lockName%>;
      >>
    case ("pthreads") then
      <<
      static pthread_mutex_t <%lockPrefix%>_<%lockName%>;
      >>
    case ("pthreads_spin") then
      <<
      static pthread_spinlock_t <%lockPrefix%>_<%lockName%>;
      >>
end function_HPCOM_createLockByLockName;

template function_HPCOM_assignLockByDepTask(Task depTask, String lockPrefix, String iType)
::=
  let lockName = function_HPCOM_getLockNameByDepTask(depTask)
  <<
  <%function_HPCOM_assignLockByLockName(lockName, lockPrefix, iType)%>
  >>
end function_HPCOM_assignLockByDepTask;

template function_HPCOM_assignLockByLockName(String lockName, String lockPrefix, String iType)
::=
  match iType
    case ("openmp") then
      <<
      omp_set_lock(&<%lockPrefix%>_<%lockName%>);
      >>
    case ("pthreads") then
      <<
      pthread_mutex_lock(&<%lockPrefix%>_<%lockName%>);
      >>
    case ("pthreads_spin") then
      <<
      pthread_spin_lock(&<%lockPrefix%>_<%lockName%>);
      >>
end function_HPCOM_assignLockByLockName;

template function_HPCOM_releaseLockByDepTask(Task depTask, String lockPrefix, String iType)
::=
  let lockName = function_HPCOM_getLockNameByDepTask(depTask)
  <<
  <%function_HPCOM_releaseLockByLockName(lockName, lockPrefix, iType)%>
  >>
end function_HPCOM_releaseLockByDepTask;

template function_HPCOM_releaseLockByLockName(String lockName, String lockPrefix, String iType)
::=
  match iType
    case ("openmp") then
      <<
      omp_unset_lock(&<%lockPrefix%>_<%lockName%>);
      >>
    case ("pthreads") then
      <<
      pthread_mutex_unlock(&<%lockPrefix%>_<%lockName%>);
      >>
    case ("pthreads_spin") then
      <<
      pthread_spin_unlock(&<%lockPrefix%>_<%lockName%>);
      >>
end function_HPCOM_releaseLockByLockName;

template functionXXX_system0_HPCOM_PThread_func(list<SimEqSystem> derivativEquations, String name, Integer n, array<list<Task>> threadTasks, String iType, Integer idx, String modelNamePrefixStr)
::=
  let taskEqs = functionXXX_system0_HPCOM_Thread0(derivativEquations, name, arrayGet(threadTasks,intAdd(idx,1)), iType, modelNamePrefixStr); separator="\n"
  let assLock = function_HPCOM_assignLockByLockName(idx, "th_lock", "pthreads"); separator="\n"
  let relLock = function_HPCOM_releaseLockByLockName(idx, "th_lock1", "pthreads"); separator="\n"
  <<
  void function<%name%>_system<%n%>_thread_<%idx%>(DATA *data, threadData_t *threadData)
  {
    MMC_TRY_TOP()
    while(1)
    {
      <%assLock%>

      if(finished)
         return;

      <%taskEqs%>
      <%relLock%>
    }
    MMC_CATCH_TOP(return;) /* No exit status?? */
  }
  >>
end functionXXX_system0_HPCOM_PThread_func;

template functionXXX_system0_HPCOM_PThread_call(String name, Integer n, Integer idx)
::=
  <<
  GC_pthread_create(&odeThread_<%idx%>, NULL, function<%name%>_system<%n%>_thread_<%idx%>, data);
  >>
end functionXXX_system0_HPCOM_PThread_call;

template functionXXX_system0_HPCOM_PThread_decl(Integer idx)
::=
  <<
  static pthread_t odeThread_<%idx%>;
  >>
end functionXXX_system0_HPCOM_PThread_decl;

template functionXXX_system0_HPCOM_PThread_start(Integer idx)
::=
  <<
  pthread_mutex_lock(&th_unlock_<%idx%>);
  >>
end functionXXX_system0_HPCOM_PThread_start;

template equationNamesHPCOM_Thread_(Integer idx, list<SimEqSystem> derivativEquations, Context context, String modelNamePrefixStr)
 "Generates an equation.
  This template should not be used for a SES_RESIDUAL.
  Residual equations are handled differently."
::=
match context
case SIMULATION_CONTEXT(genDiscrete=true) then
 match getSimCodeEqByIndex(derivativEquations, idx)
  case e as SES_ALGORITHM(statements={})
  then ""
  else
  let ix = equationIndex(getSimCodeEqByIndex(derivativEquations, idx))
  <<
  <%symbolName(modelNamePrefixStr,"eqFunction")%>_<%ix%>(data, threadData);
  >>
else
 match getSimCodeEqByIndex(derivativEquations, idx)
  case e as SES_ALGORITHM(statements={})
  then ""
  else
  let ix = equationIndex(getSimCodeEqByIndex(derivativEquations, idx))
  <<
  <%symbolName(modelNamePrefixStr,"eqFunction")%>_<%ix%>(data, threadData);
  >>
end equationNamesHPCOM_Thread_;

//----------------------------------
// End: Modified functions for HpcOm
//----------------------------------

template functionXXX_system(list<SimEqSystem> derivativEquations, String name, Integer n, String modelNamePrefixStr)
::=
  let odeEqs = derivativEquations |> eq => equationNames_(eq,contextSimulationNonDiscrete,modelNamePrefixStr); separator="\n"
  let forwardEqs = derivativEquations |> eq => equationForward_(eq,contextSimulationNonDiscrete,modelNamePrefixStr); separator="\n"
  <<

  /* forwarded equations */
  <%forwardEqs%>

  static void function<%name%>_system<%n%>(DATA *data, threadData_t *threadData)
  {
    <%odeEqs%>
  }
  >>
end functionXXX_system;

template functionXXX_systems(list<list<SimEqSystem>> eqs, String name, Text &loop, Text &varDecls, String modelNamePrefixStr)
::=
  let funcs = (eqs |> eq hasindex i0 fromindex 0 => functionXXX_system(eq,name,i0,modelNamePrefixStr) ; separator="\n")
  match listLength(eqs)
  case 0 then //empty case
    let &loop +=
        <<
        /* no <%name%> systems */
        >>
    ""
  case 1 then //1 function
    let &loop +=
        <<
        function<%name%>_system0(data, threadData);
        >>
    funcs //just the one function
  case nFuncs then //2 and more
    let funcNames = eqs |> e hasindex i0 fromindex 0 => 'function<%name%>_system<%i0%>' ; separator=",\n"
    let &varDecls += 'int id;<%\n%>'

    let &loop +=
      /* Text for the loop body that calls the equations */
      <<
      for(id=0; id<<%nFuncs%>; id++) {
        function<%name%>_systems[id](data, threadData);
      }
      >>
    /* Text before the function head */
    <<
    <%funcs%>
    OMC_DISABLE_OPT
    static void (*function<%name%>_systems[<%nFuncs%>])(DATA *, threadData_t *threadData) = {
      <%funcNames%>
    };
    >>
end functionXXX_systems;


template functionDAEModeEquationsMultiFiles(list<SimEqSystem> inEqs, Integer numEqs, Integer equationsPerFile, Context context, String fileNamePrefix, String fullPathPrefix, String modelNamePrefix, String funcName, String partName, Text &eqFuncs, Boolean static, Boolean noOpt, Boolean init)
::=
  let &file = buffer ""
  let &forwardEqs = buffer ""
  let multiFile = if intGt(numEqs, equationsPerFile) then "x"
  let fncalls = (List.balancedPartition(inEqs, equationsPerFile) |> eqs hasindex i0 =>
                  // To file
                  let &file += ((if multiFile then
                    (let fileName = addFunctionIndex('<%fileNamePrefix%>_<%partName%>_part', ".c")
                    redirectToFile(fullPathPrefix + fileName) +
                  <<
                  <%simulationFileHeader(fileNamePrefix)%>
                  #if defined(__cplusplus)
                  extern "C" {
                  #endif<%\n%>
                  >>)) +
                  (eqs |> eq => (equation_impl_options(-1, -1, eq, context, modelNamePrefix, static, noOpt, init); separator="\n")
                  ) +
                  <<
                  >>
                  +
                  (if multiFile then
                  (<<

                  #if defined(__cplusplus)
                  }
                  #endif
                  >> +
                  closeFile())))

                  let &forwardEqs +=
                      if multiFile then
                       ("\n/* --- forward equations --- */\n" +
                        (eqs |> eq => equationForward_(eq, context, modelNamePrefix); separator="\n") +
                        "\n\n")

                  // fncalls
                  '<%(eqs |> eq => equationNames_(eq, context, modelNamePrefix); separator="\n")%>'

                  )


  let &eqFuncs += forwardEqs + file
  fncalls
end functionDAEModeEquationsMultiFiles;

template createEquationsAndCalls(list<list<SimEqSystem>> systems, String name, Context context, String fileNamePrefix, String fullPathPrefix, String modelNamePrefix, Text eqCalls, Text eqFuncs)
::=
  let _ = (systems |> equations => (
          let fncalls = functionDAEModeEquationsMultiFiles(equations, listLength(equations),
                Flags.getConfigInt(Flags.EQUATIONS_PER_FILE), context, fileNamePrefix, fullPathPrefix, modelNamePrefix,
                "evaluateDAEResiduals", "16dae", &eqFuncs, /* Static? */ false, true /* No optimization */, /* initial? */ false)
          let &eqCalls += fncalls
          <<>>
        )
      )
  <<>>
end createEquationsAndCalls;

template equationNamesArrayFormat(SimEqSystem eq, Context context, String name, Integer arrayIndex, Text &arrayEqs, Text &forwardEqs, String modelNamePrefixStr)
 "Generates an equation.
  This template should not be used for a SES_RESIDUAL.
  Residual equations are handled differently."
::=
match context
case SIMULATION_CONTEXT(genDiscrete=true) then
 match eq
  case e as SES_ALGORITHM(statements={})
  then ""
  else
  let ix = equationIndex(eq)
  let &arrayEqs += '<%symbolName(modelNamePrefixStr,"eqFunction")%>_<%ix%>,<%\n%>'
  let &forwardEqs += 'extern void <%symbolName(modelNamePrefixStr,"eqFunction")%>_<%ix%>(DATA* data, threadData_t *threadData);<%\n%>'
  <<
  <% if profileAll() then 'SIM_PROF_TICK_EQ(<%ix%>);' %>
  function<%name%>_systems[<%arrayIndex%>](data);
  <% if profileAll() then 'SIM_PROF_ACC_EQ(<%ix%>);' %>
  >>
else
 match eq
  case e as SES_ALGORITHM(statements={})
  then ""
  else
  let ix = equationIndex(eq)
  let &arrayEqs += '<%symbolName(modelNamePrefixStr,"eqFunction")%>_<%ix%>,<%\n%>'
  let &forwardEqs += 'extern void <%symbolName(modelNamePrefixStr,"eqFunction")%>_<%ix%>(DATA* data, threadData_t *threadData);<%\n%>'
  <<
  <% if profileAll() then 'SIM_PROF_TICK_EQ(<%ix%>);' %>
  // <%symbolName(modelNamePrefixStr,"eqFunction")%>_<%ix%>(data, threadData);
  function<%name%>_systems[<%arrayIndex%>](data);
  <% if profileAll() then 'SIM_PROF_ACC_EQ(<%ix%>);' %>
  >>
end equationNamesArrayFormat;

template functionXXX_systems_arrayFormat(list<list<SimEqSystem>> eqlstlst, String name, Text &fncalls, Text &nrfuncs, Text &varDecls, String modelNamePrefixStr)
::=
match eqlstlst
  case ({})
  case ({{}}) then
  let &nrfuncs += "0"
  <<
  /* no <%name%> systems */
  static void (**function<%name%>_systems)(DATA *,  threadData_t *) = NULL;
  >>

  case eqlstlst as ({eqlst}) then
    let &nrfuncs += listLength(eqlst)
    let &arrayEqs = buffer ""
    let &forwardEqs = buffer ""
    let &fncalls += (eqlst |> eq hasindex i0 => equationNamesArrayFormat(eq,contextSimulationNonDiscrete,name,i0,arrayEqs,forwardEqs,modelNamePrefixStr); separator="\n")
    <<
    /* forwarded equations */
    <%forwardEqs%>

    static void (*function<%name%>_systems[<%nrfuncs%>])(DATA *,  threadData_t *) = {
      <%arrayEqs%>
    };

    >>

  case eqlstlst as ({eqlst::_}) then
  error(sourceInfo(), 'TODO more than ODE list in <%name%> systems')
end functionXXX_systems_arrayFormat;

template functionODE(list<list<SimEqSystem>> derivativEquations, Text method, Option<tuple<Schedule,Schedule,Schedule>> hpcOmSchedules, String modelNamePrefix)
 "Generates function in simulation file."
::=
  let () = System.tmpTickReset(0)
  let &nrfuncs = buffer ""
  let &varDecls2 = buffer ""
  let &varDecls = buffer ""
  let &fncalls = buffer ""
  let systems = if Flags.isSet(Flags.HPCOM) then
                    (functionXXX_systems_HPCOM(derivativEquations, "ODE", &fncalls, &varDecls, hpcOmSchedules, modelNamePrefix))
                else if Flags.getConfigBool(Flags.PARMODAUTO) then
                    (functionXXX_systems_arrayFormat(derivativEquations, "ODE", &fncalls, &nrfuncs, &varDecls, modelNamePrefix))
                else
                    (functionXXX_systems(derivativEquations, "ODE", &fncalls, &varDecls, modelNamePrefix))
  /* let systems = functionXXX_systems(derivativEquations, "ODE", &fncalls, &varDecls) */
  let &tmp = buffer ""
  <<
  <%tmp%>
  <%systems%>

  int <%symbolName(modelNamePrefix,"functionODE")%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH
  #if !defined(OMC_MINIMAL_RUNTIME)
    <% if profileFunctions() then "" else "if (measure_time_flag) " %>rt_tick(SIM_TIMER_FUNCTION_ODE);
  #endif

    <%varDecls%>

    data->simulationInfo->callStatistics.functionODE++;

    <%symbolName(modelNamePrefix,"functionLocalKnownVars")%>(data, threadData);
    <%if Flags.getConfigBool(Flags.PARMODAUTO) then 'PM_evaluate_ODE_system(pm_model);'
    else fncalls %>

  #if !defined(OMC_MINIMAL_RUNTIME)
    <% if profileFunctions() then "" else "if (measure_time_flag) " %>rt_accumulate(SIM_TIMER_FUNCTION_ODE);
  #endif

    TRACE_POP
    return 0;
  }
  >>
end functionODE;

template functionAlgebraic(list<list<SimEqSystem>> algebraicEquations, String modelNamePrefix)
  "Generates function in simulation file."
::=
  let &varDecls = buffer ""
  let &fncalls = buffer ""
  let systems = functionXXX_systems(algebraicEquations, "Alg", &fncalls, &varDecls, modelNamePrefix)


  <<
  <%systems%>
  /* for continuous time variables */
  int <%symbolName(modelNamePrefix,"functionAlgebraics")%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH
    <%varDecls%>

  #if !defined(OMC_MINIMAL_RUNTIME)
    <% if profileFunctions() then "" else "if (measure_time_flag) " %>rt_tick(SIM_TIMER_ALGEBRAICS);
  #endif
    data->simulationInfo->callStatistics.functionAlgebraics++;

    <%symbolName(modelNamePrefix,"function_savePreSynchronous")%>(data, threadData);

    <%fncalls %>

  #if !defined(OMC_MINIMAL_RUNTIME)
    <% if profileFunctions() then "" else "if (measure_time_flag) " %>rt_accumulate(SIM_TIMER_ALGEBRAICS);
  #endif

    TRACE_POP
    return 0;
  }
  >>
end functionAlgebraic;

template evaluateDAEResiduals(list<list<SimEqSystem>> resEquations, String fileNamePrefix, String fullPathPrefix, String modelNamePrefix)
  "Generates function in simulation file."
::=
  let () = System.tmpTickReset(0)
  let &eqFuncs = buffer ""
  let &eqCalls = buffer ""

  let systems = createEquationsAndCalls(resEquations, "DAERes", contextDAEmode, fileNamePrefix, fullPathPrefix, modelNamePrefix, &eqCalls, &eqFuncs)
  <<
  /*residual equations*/
  <%eqFuncs%>

  /* for residuals DAE variables */
  OMC_DISABLE_OPT
  int <%symbolName(modelNamePrefix,"evaluateDAEResiduals")%>(DATA *data, threadData_t *threadData, int currentEvalStage)
  {
    TRACE_PUSH
    int evalStages;
    data->simulationInfo->callStatistics.functionEvalDAE++;

  #if !defined(OMC_MINIMAL_RUNTIME)
    <% if profileFunctions() then "" else "if (measure_time_flag) " %>rt_tick(SIM_TIMER_DAE);
  #endif

    <%eqCalls%>

  #if !defined(OMC_MINIMAL_RUNTIME)
    <% if profileFunctions() then "" else "if (measure_time_flag) " %>rt_accumulate(SIM_TIMER_DAE);
  #endif

    TRACE_POP
    return 0;
  }
  >>
end evaluateDAEResiduals;

template genVarIndexes(list<SimVar> vars, String arrayName)
"This template generates array with indexes of given variables."
::=
  let size = listLength(vars)
  let varIndexes = ( vars |> var =>
    (match var
    case SIMVAR(__) then
      '<%crefToIndex(name)%>'
    end match)
   ;separator=",")
  <<
  const int <%arrayName%>[<%size%>] = {<%varIndexes%>};
  >>
end genVarIndexes;


template initializeDAEmodeData(Integer nResVars, list<SimVar> algVars, Integer nAuxVars, SparsityPattern sparsepattern, list<list<Integer>> colorList, Integer maxColor, String modelNamePrefix)
  "Generates initialization function for daeMode."
::=
  let nAlgVars = listLength(algVars)
  let sizeCols = listLength(sparsepattern)
  let sizeNNZ = lengthListElements(unzipSecond(sparsepattern))
  let colPtr = genSPCRSPtr(listLength(sparsepattern), sparsepattern, "colPtrIndex")
  let rowIndex = genSPCRSRows(lengthListElements(unzipSecond(sparsepattern)), sparsepattern, "rowIndex")
  let colorString = genSPColors(colorList, "daeModeData->sparsePattern->colorCols")
  let maxColorStr = '<%maxColor%>'
  let algIndexes = genVarIndexes(algVars, "algIndexes")
  <<
  /* initialize the daeMode variables */
  OMC_DISABLE_OPT
  int <%symbolName(modelNamePrefix,"initializeDAEmodeData")%>(DATA* data, DAEMODE_DATA* daeModeData)
  {
    TRACE_PUSH
    /* sparse patterns */
    <%colPtr%>
    <%rowIndex%>
    <%algIndexes%>
    int i = 0;

    daeModeData->nResidualVars = <%nResVars%>;
    daeModeData->nAlgebraicDAEVars = <%nAlgVars%>;
    daeModeData->nAuxiliaryVars = <%nAuxVars%>;

    daeModeData->residualVars = (double*) malloc(sizeof(double)*<%nResVars%>);
    daeModeData->auxiliaryVars = (double*) malloc(sizeof(double)*<%nAuxVars%>);

    /* set the function pointer */
    daeModeData->evaluateDAEResiduals = <%symbolName(modelNamePrefix,"evaluateDAEResiduals")%>;

    /* prepare algebraic indexes */
    daeModeData->algIndexes = (int*) malloc(sizeof(int)*<%nAlgVars%>);
    memcpy(daeModeData->algIndexes, algIndexes, <%nAlgVars%>*sizeof(int));
    /* intialize sparse pattern */
    daeModeData->sparsePattern = allocSparsePattern(<%sizeCols%>, <%sizeNNZ%>, <%maxColor%>);

    /* write lead index of compressed sparse column */
    memcpy(daeModeData->sparsePattern->leadindex, colPtrIndex, (1+<%sizeCols%>)*sizeof(int));
    /* makek CRS compatible */
    for(i=2;i<<%sizeCols%>+1;++i)
      daeModeData->sparsePattern->leadindex[i] += daeModeData->sparsePattern->leadindex[i-1];
    /* call sparse index */
    memcpy(daeModeData->sparsePattern->index, rowIndex, <%sizeNNZ%>*sizeof(int));

    /* write color array */
    <%colorString%>
    TRACE_POP
    return 0;
  }
  >>
end initializeDAEmodeData;

template functionDAE(list<SimEqSystem> allEquationsPlusWhen, String modelNamePrefix)
  "Generates function in simulation file.
  This is a helper of template simulationFile."
::=
  let &eqfuncs = buffer ""
  let fncalls = (allEquationsPlusWhen |> eq =>
                    let &eqfuncs += equation_impl(-1, -1, eq, contextSimulationDiscrete, modelNamePrefix, false)
                    equation_call(eq, modelNamePrefix)
                    ;separator="\n")


  <<

  <%&eqfuncs%>

  >>
end functionDAE;

template functionLocalKnownVars(list<SimEqSystem> localKnownVars, String modelNamePrefix)
  "Generates function in simulation file.
  This is a helper of template simulationFile."
::=
  <<
  <%(localKnownVars |> eq =>
                    equation_impl(-1, -1, eq, contextSimulationDiscrete, modelNamePrefix, false)
                    ;separator="\n")%>

  int <%symbolName(modelNamePrefix,"functionLocalKnownVars")%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH

    <%(localKnownVars |> eq =>
                    equation_call(eq, modelNamePrefix)
                    ;separator="\n")%>

    TRACE_POP
    return 0;
  }
  >>
end functionLocalKnownVars;

template functionZeroCrossing(list<ZeroCrossing> zeroCrossings, list<SimEqSystem> equationsForZeroCrossings, String modelNamePrefix)
"template functionZeroCrossing
  Generates function for ZeroCrossings in simulation file.
  This is a helper of template simulationFile."
::=
  let &auxFunction = buffer ""
  let forwardEqs = equationsForZeroCrossings |> eq => equationForward_(eq,contextSimulationNonDiscrete,modelNamePrefix); separator="\n"

  let &varDecls2 = buffer ""
  let zeroCrossingsCode = zeroCrossingsTpl(zeroCrossings, &varDecls2, &auxFunction)

  let resDesc = (zeroCrossings |> ZERO_CROSSING(__) =>
    let &descStr = buffer '<%Util.escapeModelicaStringToCString(dumpExp(relation_,""))%>"'
    <<<%descriptionString(&descStr, iter)%>>>
    ;separator=",\n")

  let desc = match zeroCrossings
             case {} then
               <<
               const char *<%symbolName(modelNamePrefix,"zeroCrossingDescription")%>(int i, int **out_EquationIndexes)
               {
                 *out_EquationIndexes = NULL;
                 return "empty";
               }
               >>
             else
               <<
               const char *<%symbolName(modelNamePrefix,"zeroCrossingDescription")%>(int i, int **out_EquationIndexes)
               {
                 static const char *res[] = {<%resDesc%>};
                 <%zeroCrossings |> ZERO_CROSSING(__) =>
                   'static const int occurEqs<%index%>[] = {<%listLength(occurEquLst)%><%occurEquLst |> i => ',<%i%>'%>};' ; separator = "\n"%>
                 static const int *occurEqs[] = {<%zeroCrossings |> ZERO_CROSSING(__) => 'occurEqs<%index%>' ; separator = ","%>};
                 *out_EquationIndexes = (int*) occurEqs[i];
                 return res[i];
               }
               >>

  <<
  <%desc%>

  /* forwarded equations */
  <%forwardEqs%>

  int <%symbolName(modelNamePrefix,"function_ZeroCrossingsEquations")%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH

    data->simulationInfo->callStatistics.functionZeroCrossingsEquations++;

    <%(equationsForZeroCrossings |> eq => equation_call(eq, modelNamePrefix) ; separator="\n")%>

    TRACE_POP
    return 0;
  }

  int <%symbolName(modelNamePrefix,"function_ZeroCrossings")%>(DATA *data, threadData_t *threadData, double *gout)
  {
    TRACE_PUSH
    const int *equationIndexes = NULL;

    <%varDecls2%>

  #if !defined(OMC_MINIMAL_RUNTIME)
    <% if profileFunctions() then "" else "if (measure_time_flag) " %>rt_tick(SIM_TIMER_ZC);
  #endif
    data->simulationInfo->callStatistics.functionZeroCrossings++;

    <%zeroCrossingsCode%>

  #if !defined(OMC_MINIMAL_RUNTIME)
    <% if profileFunctions() then "" else "if (measure_time_flag) " %>rt_accumulate(SIM_TIMER_ZC);
  #endif

    TRACE_POP
    return 0;
  }
  >>
end functionZeroCrossing;

template descriptionString(Text &descStr, Option<list<SimIterator>> iter)
::=
  match iter
    case SOME(iter_) then (List.intRange(SimCodeUtil.getSimIteratorSize(iter_)) |> idx =>
      '"[<%idx%>] <%descStr%>';separator=",\n")
    else <<"<%descStr%>>>
end descriptionString;

template zeroCrossingsTpl(list<ZeroCrossing> zeroCrossings, Text &varDecls, Text &auxFunction)
 "Generates code for zero crossings."
::=
  (zeroCrossings |> ZERO_CROSSING(__) =>
    zeroCrossingTpl(index, relation_, iter, &varDecls, &auxFunction)
  ;separator="\n";empty)
end zeroCrossingsTpl;


template zeroCrossingTpl(Integer index1, Exp relation, Option<list<SimIterator>> iter, Text &varDecls, Text &auxFunction)
 "Generates code for a zero crossing."
::=
  let &preExp = buffer ""
  let &sub = buffer ""
  let forHead = match iter
    case SOME(iter_) then (iter_ |> it as SIM_ITERATOR(__) =>
      forIterator(it, contextZeroCross, &preExp, &varDecls, &auxFunction, &sub)
      ;separator="\n";empty)
    else ""
  let forBody = match iter
    case SOME(iter_) then <<int tmp = <%(iter_ |> it =>
      forIteratorBody(it, contextZeroCross, &preExp, &varDecls, &auxFunction, &sub)
      ;separator = "")%>0<%(iter_ |> it => ")";separator = "")%>;>>
    else ""
  let tmp_ = match iter case SOME(iter_) then "+tmp" else ""
  let forTail = match iter
    case SOME(iter_) then (iter_ |> it as SIM_ITERATOR(__) => "}";separator="\n";empty)
    else ""
  match relation
  case exp as RELATION(__) then
    let e1 = daeExp(exp, contextZeroCross, &preExp, &varDecls, &auxFunction)
    <<
    <%forHead%>
    <%preExp%>
    <%forBody%>
    gout[<%index1%><%tmp_%>] = (<%e1%>) ? 1 : -1;
    <%forTail%>
    >>
  case (exp1 as LBINARY(__)) then
    let e1 = daeExp(exp1, contextZeroCross, &preExp, &varDecls, &auxFunction)
    <<
    <%forHead%>
    <%preExp%>
    <%forBody%>
    gout[<%index1%><%tmp_%>] = (<%e1%>) ? 1 : -1;
    <%forTail%>
    >>
  case (exp1 as LUNARY(__)) then
    let e1 = daeExp(exp1, contextZeroCross, &preExp, &varDecls, &auxFunction)
    <<
    <%forHead%>
    <%preExp%>
    <%forBody%>
    gout[<%index1%><%tmp_%>] = (<%e1%>) ? 1 : -1;
    <%forTail%>
    >>
  case CALL(path=IDENT(name="sample"), expLst={_, start, interval}) then
    << >>
  case CALL(path=IDENT(name="integer"), expLst={exp1, idx}) then
    let e1 = daeExp(exp1, contextZeroCross, &preExp, &varDecls, &auxFunction)
    let indx = daeExp(idx, contextZeroCross, &preExp, &varDecls, &auxFunction)
    <<
    <%forHead%>
    <%preExp%>
    <%forBody%>
    gout[<%index1%><%tmp_%>] = (floor(<%e1%>) != floor(data->simulationInfo->mathEventsValuePre[<%indx%>])) ? 1 : -1;
    <%forTail%>
    >>
  case CALL(path=IDENT(name="floor"), expLst={exp1, idx}) then
    let e1 = daeExp(exp1, contextZeroCross, &preExp, &varDecls, &auxFunction)
    let indx = daeExp(idx, contextZeroCross, &preExp, &varDecls, &auxFunction)
    <<
    <%forHead%>
    <%preExp%>
    <%forBody%>
    gout[<%index1%><%tmp_%>] = (floor(<%e1%>) != floor(data->simulationInfo->mathEventsValuePre[<%indx%>])) ? 1 : -1;
    <%forTail%>
    >>
  case CALL(path=IDENT(name="ceil"), expLst={exp1, idx}) then
    let e1 = daeExp(exp1, contextZeroCross, &preExp, &varDecls, &auxFunction)
    let indx = daeExp(idx, contextZeroCross, &preExp, &varDecls, &auxFunction)
    <<
    <%forHead%>
    <%preExp%>
    <%forBody%>
    gout[<%index1%><%tmp_%>] = (ceil(<%e1%>) != ceil(data->simulationInfo->mathEventsValuePre[<%indx%>])) ? 1 : -1;
    <%forTail%>
    >>
  case CALL(path=IDENT(name="mod"), expLst={exp1, exp2, idx}) then
    let e1 = daeExp(exp1, contextZeroCross, &preExp, &varDecls, &auxFunction)
    let e2 = daeExp(exp2, contextZeroCross, &preExp, &varDecls, &auxFunction)
    let indx = daeExp(idx, contextZeroCross, &preExp, &varDecls, &auxFunction)
    let tvar1 = tempDecl("modelica_real", &varDecls)
    let tvar2 = tempDecl("modelica_real", &varDecls)
    let &preExp += '<%tvar1%> = floor((<%e1%>) / (<%e2%>));<%\n%>'
    let &preExp += '<%tvar2%> = floor((data->simulationInfo->mathEventsValuePre[<%indx%>]) / (data->simulationInfo->mathEventsValuePre[<%indx%>+1]));<%\n%>'
    <<
    <%forHead%>
    <%preExp%>
    <%forBody%>
    gout[<%index1%><%tmp_%>] = <%tvar1%> != <%tvar2%> ? 1 : -1;
    <%forTail%>
    >>
  case CALL(path=IDENT(name="div"), expLst={exp1, exp2, idx}) then
    let e1 = daeExp(exp1, contextZeroCross, &preExp, &varDecls, &auxFunction)
    let e2 = daeExp(exp2, contextZeroCross, &preExp, &varDecls, &auxFunction)
    let indx = daeExp(idx, contextZeroCross, &preExp, &varDecls, &auxFunction)
    <<
    <%forHead%>
    <%preExp%>
    <%forBody%>
    gout[<%index1%><%tmp_%>] = (trunc((<%e1%>)/(<%e2%>)) != trunc(data->simulationInfo->mathEventsValuePre[<%indx%>]/data->simulationInfo->mathEventsValuePre[<%indx%>+1])) ? 1 : -1;
    <%forTail%>
    >>
  else
    error(sourceInfo(), ' UNKNOWN ZERO CROSSING for <%index1%>')
end zeroCrossingTpl;

template functionRelations(list<ZeroCrossing> relations, String modelNamePrefix) "template functionRelations
  Generates function in simulation file.
  This is a helper of template simulationFile."
::=
  let &auxFunction = buffer ""
  let &varDecls = buffer ""
  let relationsCode = relationsTpl(relations, contextZeroCross, &varDecls, &auxFunction)
  let relationsCodeElse = relationsTpl(relations, contextOther, &varDecls, &auxFunction)

  let resDesc = (relations |> ZERO_CROSSING(__) =>
    let &descStr = buffer '<%dumpExp(relation_,"")%>"'
    <<<%descriptionString(&descStr, iter)%>>>
    ;separator=",\n")

  let desc = match relations
             case {} then
               <<
               const char *<%symbolName(modelNamePrefix,"relationDescription")%>(int i)
               {
                 return "empty";
               }
               >>
             else
               <<
               const char *<%symbolName(modelNamePrefix,"relationDescription")%>(int i)
               {
                 const char *res[] = {<%resDesc%>};
                 return res[i];
               }
               >>

  <<
  <%auxFunction%>
  <%desc%>

  int <%symbolName(modelNamePrefix,"function_updateRelations")%>(DATA *data, threadData_t *threadData, int evalforZeroCross)
  {
    TRACE_PUSH
    const int *equationIndexes = NULL;

    <%varDecls%>

    if(evalforZeroCross) {
      <%relationsCode%>
    } else {
      <%relationsCodeElse%>
    }

    TRACE_POP
    return 0;
  }
  >>
end functionRelations;

template relationsTpl(list<ZeroCrossing> relations, Context context, Text &varDecls, Text &auxFunction)
 "Generates code for zero crossings."
::=
  (relations |> ZERO_CROSSING(__) =>
    relationTpl(index, relation_, iter, context, &varDecls, &auxFunction)
  ;separator="\n";empty)
end relationsTpl;


template relationTpl(Integer index1, Exp relation, Option<list<SimIterator>> iter, Context context, Text &varDecls, Text &auxFunction)
 "Generates code for a zero crossing."
::=
let &preExp = buffer ""
  let &sub = buffer ""
  let forHead = match iter
    case SOME(iter_) then (iter_ |> it as SIM_ITERATOR(__) =>
      forIterator(it, contextZeroCross, &preExp, &varDecls, &auxFunction, &sub)
      ;separator="\n";empty)
    else ""
  let forBody = match iter
    case SOME(iter_) then <<int tmp = <%(iter_ |> it =>
      forIteratorBody(it, contextZeroCross, &preExp, &varDecls, &auxFunction, &sub)
      ;separator = "")%>0<%(iter_ |> it => ")";separator = "")%>;>>
    else ""
  let tmp_ = match iter case SOME(iter_) then "+tmp" else ""
  let forTail = match iter
    case SOME(iter_) then (iter_ |> it as SIM_ITERATOR(__) => "}";separator="\n";empty)
    else ""
  match relation
  case exp as RELATION(__) then
    let res = daeExp(exp, context, &preExp, &varDecls, &auxFunction)
    <<
    <%forHead%>
    <%preExp%>
    <%forBody%>
    data->simulationInfo->relations[<%index1%><%tmp_%>] = <%res%>;
    <%forTail%>
    >>
  else
    <<
    /* UNKNOWN Relation for <%index1%> */
    >>
end relationTpl;

template crefToPrintfArg(ComponentRef cr)
::=
  match crefType(cr)
  case "modelica_real" then "%g"
  case "modelica_integer" then "\"OMC_INT_FORMAT\""
  case "modelica_boolean" then "%d"
  case "modelica_string" then "%s"
  else error(sourceInfo(), 'Do not know what printf argument to give <%crefStr(cr)%>')
  end match
end crefToPrintfArg;

template crefType(ComponentRef cr) "template crefType
  Like cref but with cast if type is integer."
::=
  match cr
  case CREF_IDENT(__) then '<%expTypeModelica(identType)%>'
  case CREF_QUAL(__)  then '<%crefType(componentRef)%>'
  else "crefType:ERROR"
  end match
end crefType;

template crefShortType(ComponentRef cr) "template crefType
  Like cref but with cast if type is integer."
::=
  match cr
  case CREF_IDENT(__) then '<%expTypeShort(identType)%>'
  case CREF_QUAL(__)  then '<%crefShortType(componentRef)%>'
  else "crefType:ERROR"
  end match
end crefShortType;

template functionAssertsforCheck(list<SimEqSystem> algAndEqAssertsEquations, String modelNamePrefix) "template functionAssertsforCheck
  Generates function in simulation file.
  This is a helper of template simulationFile."
::=
  <<
  <%(algAndEqAssertsEquations |> eq =>
    equation_impl(-1, -1, eq, contextSimulationDiscrete, modelNamePrefix, false)
    ;separator="\n")%>
  /* function to check assert after a step is done */
  OMC_DISABLE_OPT
  int <%symbolName(modelNamePrefix,"checkForAsserts")%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH

    <%(algAndEqAssertsEquations |> eq =>
    equation_call(eq, modelNamePrefix)
    ;separator="\n")%>

    TRACE_POP
    return 0;
  }
  >>
end functionAssertsforCheck;

template functionlinearmodel(ModelInfo modelInfo, String modelNamePrefix) "template functionlinearmodel
  Generates function in simulation file."
::=
  match modelInfo
  case MODELINFO(varInfo=VARINFO(__), vars=SIMVARS(__)) then
    let matrixA = genMatrix("A", "n", "n", varInfo.numStateVars, varInfo.numStateVars)
    let matrixB = genMatrix("B", "n", "m", varInfo.numStateVars, varInfo.numInVars)
    let matrixC = genMatrix("C", "p", "n", varInfo.numOutVars, varInfo.numStateVars)
    let matrixD = genMatrix("D", "p", "m", varInfo.numOutVars, varInfo.numInVars)
    let matrixCz = genMatrix("Cz", "nz", "n", varInfo.numAlgVars, varInfo.numStateVars)
    let matrixDz = genMatrix("Dz", "nz", "m", varInfo.numAlgVars, varInfo.numInVars)
    let vectorX = genVector("x", "n", varInfo.numStateVars, 0)
    let vectorU = genVector("u", "m", varInfo.numInVars, 1)
    let vectorY = genVector("y", "p", varInfo.numOutVars, 2)
    let vectorZ = genVector("z", "nz", varInfo.numAlgVars, 2)
    //string def_proctedpart("\n  Real x[<%varInfo.numStateVars%>](start=x0);\n  Real u[<%varInfo.numInVars%>](start=u0);\n  output Real y[<%varInfo.numOutVars%>];\n");
    <<
    const char *<%symbolName(modelNamePrefix,"linear_model_frame")%>()
    {
      return "model linearized_model \"<%modelNamePrefix%>\"\n"
      "  parameter Integer n = <%varInfo.numStateVars%> \"number of states\";\n"
      "  parameter Integer m = <%varInfo.numInVars%> \"number of inputs\";\n"
      "  parameter Integer p = <%varInfo.numOutVars%> \"number of outputs\";\n"
      "  parameter Real x0[n] = %s;\n"
      "  parameter Real u0[m] = %s;\n"
      "\n"
      <%matrixA%>
      <%matrixB%>
      <%matrixC%>
      <%matrixD%>
      "\n"
      <%vectorX%>
      <%vectorU%>
      <%vectorY%>
      "\n"
      <%getVarName(vars.stateVars, "x")%>
      <%getVarName(vars.inputVars, "u")%>
      <%getVarName(vars.outputVars, "y")%>
      "equation\n"
      "  der(x) = A * x + B * u;\n"
      "  y = C * x + D * u;\n"
      "end linearized_model;\n";
    }
    const char *<%symbolName(modelNamePrefix,"linear_model_datarecovery_frame")%>()
    {
      return "model linearized_model \"<%modelNamePrefix%>\"\n"
      "  parameter Integer n = <%varInfo.numStateVars%> \"number of states\";\n"
      "  parameter Integer m = <%varInfo.numInVars%> \"number of inputs\";\n"
      "  parameter Integer p = <%varInfo.numOutVars%> \"number of outputs\";\n"
      "  parameter Integer nz = <%varInfo.numAlgVars%> \"data recovery variables\";\n"
      "  parameter Real x0[<%varInfo.numStateVars%>] = %s;\n"
      "  parameter Real u0[<%varInfo.numInVars%>] = %s;\n"
      "  parameter Real z0[<%varInfo.numAlgVars%>] = %s;\n"
      "\n"
      <%matrixA%>
      <%matrixB%>
      <%matrixC%>
      <%matrixD%>
      <%matrixCz%>
      <%matrixDz%>
      "\n"
      <%vectorX%>
      <%vectorU%>
      <%vectorY%>
      <%vectorZ%>
      "\n"
      <%getVarName(vars.stateVars, "x")%>
      <%getVarName(vars.inputVars, "u")%>
      <%getVarName(vars.outputVars, "y")%>
      <%getVarName(vars.algVars, "z")%>
      "equation\n"
      "  der(x) = A * x + B * u;\n"
      "  y = C * x + D * u;\n"
      "  z = Cz * x + Dz * u;\n"
      "end linearized_model;\n";
    }
    >>
  end match
end functionlinearmodel;

template functionlinearmodelMatlab(ModelInfo modelInfo, String modelNamePrefix) "template functionlinearmodelMatlab
  Generates matlab functions in simulation file."
::=
  match modelInfo
  case MODELINFO(varInfo=VARINFO(__), vars=SIMVARS(__)) then
    let matrixA = genMatrixMatlab("A", "n", "n", varInfo.numStateVars, varInfo.numStateVars)
    let matrixB = genMatrixMatlab("B", "n", "m", varInfo.numStateVars, varInfo.numInVars)
    let matrixC = genMatrixMatlab("C", "p", "n", varInfo.numOutVars, varInfo.numStateVars)
    let matrixD = genMatrixMatlab("D", "p", "m", varInfo.numOutVars, varInfo.numInVars)
    //string def_proctedpart("\n  Real x[<%varInfo.numStateVars%>](start=x0);\n  Real u[<%varInfo.numInVars%>](start=u0);\n  output Real y[<%varInfo.numOutVars%>];\n");
    <<
    const char *<%symbolName(modelNamePrefix,"linear_model_frame")%>()
    {
      return "function [A, B, C, D, stateVars, inputVars, outputVars] = linearized_model()\n"
      "%% <%modelNamePrefix%>\n"
      "%% der(x) = A * x + B * u\n"
      "%% y = C * x + D * u\n"
      "  n = <%varInfo.numStateVars%>; %% number of states\n"
      "  m = <%varInfo.numInVars%>; %% number of inputs\n"
      "  p = <%varInfo.numOutVars%>; %% number of outputs\n"
      "\n"
      "  x0 = %s;\n"
      "  u0 = %s;\n"
      "\n"
      <%matrixA%>
      <%matrixB%>
      <%matrixC%>
      <%matrixD%>
      "  stateVars  = {<%getVarNameMatlab(vars.stateVars, "x0")%>};\n"
      "  inputVars  = {<%getVarNameMatlab(vars.inputVars, "u0")%>};\n"
      "  outputVars = {<%getVarNameMatlab(vars.outputVars, "y0")%>};\n"
      "  Ts = %g; %% stop time\n\n"
      "end";
    }
    const char *<%symbolName(modelNamePrefix,"linear_model_datarecovery_frame")%>()
    {
    }
    >>
  end match
end functionlinearmodelMatlab;

template functionlinearmodelJulia(ModelInfo modelInfo, String modelNamePrefix) "template functionlinearmodelJulia
  Generates julia functions in simulation file."
::=
  match modelInfo
  case MODELINFO(varInfo=VARINFO(__), vars=SIMVARS(__)) then
    let matrixA = genMatrixJulia("A", "n", "n", varInfo.numStateVars, varInfo.numStateVars)
    let matrixB = genMatrixJulia("B", "n", "m", varInfo.numStateVars, varInfo.numInVars)
    let matrixC = genMatrixJulia("C", "p", "n", varInfo.numOutVars, varInfo.numStateVars)
    let matrixD = genMatrixJulia("D", "p", "m", varInfo.numOutVars, varInfo.numInVars)
    let matrixCz = genMatrixJulia("Cz", "nz", "n", varInfo.numAlgVars, varInfo.numStateVars)
    let matrixDz = genMatrixJulia("Dz", "nz", "m", varInfo.numAlgVars, varInfo.numInVars)
    //string def_proctedpart("\n  Real x[<%varInfo.numStateVars%>](start=x0);\n  Real u[<%varInfo.numInVars%>](start=u0);\n  output Real y[<%varInfo.numOutVars%>];\n");
    <<
    const char *<%symbolName(modelNamePrefix,"linear_model_frame")%>()
    {
      return "function linearized_model()\n"
      "  # <%modelNamePrefix%> #\n"
      "  local n = <%varInfo.numStateVars%> # number of states \n"
      "  local m = <%varInfo.numInVars%> # number of inputs \n"
      "  local p = <%varInfo.numOutVars%> # number of outputs \n"
      "\n"
      "  local x0 = %s\n"
      "  local u0 = %s\n"
      "\n"
      <%matrixA%>
      <%matrixB%>
      <%matrixC%>
      <%matrixD%>
      "  stateVars  = [<%getVarNameJulia(vars.stateVars, "x0")%>]\n"
      "  inputVars  = [<%getVarNameJulia(vars.inputVars, "u0")%>]\n"
      "  outputVars = [<%getVarNameJulia(vars.outputVars, "y0")%>]\n"
      "  Ts = %g; #stop time\n\n"
      "\n"
      "  return (n, m, p, x0, u0, A, B, C, D, stateVars, inputVars, outputVars)\n"
      "end";
    }
    const char *<%symbolName(modelNamePrefix,"linear_model_datarecovery_frame")%>()
    {
    }
    >>
  end match
end functionlinearmodelJulia;

template functionlinearmodelPython(ModelInfo modelInfo, String modelNamePrefix) "template functionlinearmodelPython
  Generates python functions in simulation file."
::=
  match modelInfo
  case MODELINFO(varInfo=VARINFO(__), vars=SIMVARS(__)) then
    let matrixA = genMatrixPython("A", "n", "n", varInfo.numStateVars, varInfo.numStateVars)
    let matrixB = genMatrixPython("B", "n", "m", varInfo.numStateVars, varInfo.numInVars)
    let matrixC = genMatrixPython("C", "p", "n", varInfo.numOutVars, varInfo.numStateVars)
    let matrixD = genMatrixPython("D", "p", "m", varInfo.numOutVars, varInfo.numInVars)
    let matrixCz = genMatrixPython("Cz", "nz", "n", varInfo.numAlgVars, varInfo.numStateVars)
    let matrixDz = genMatrixPython("Dz", "nz", "m", varInfo.numAlgVars, varInfo.numInVars)
    //string def_proctedpart("\n  Real x[<%varInfo.numStateVars%>](start=x0);\n  Real u[<%varInfo.numInVars%>](start=u0);\n  output Real y[<%varInfo.numOutVars%>];\n");
    <<
    const char *<%symbolName(modelNamePrefix,"linear_model_frame")%>()
    {
      return "def linearized_model():\n"
      "    # <%modelNamePrefix%>\n"
      "    # der(x) = A * x + B * u \n"
      "    # y = C * x + D * u \n"
      "    n = <%varInfo.numStateVars%> # number of states\n"
      "    m = <%varInfo.numInVars%> # number of inputs\n"
      "    p = <%varInfo.numOutVars%> # number of outputs\n"
      "\n"
      "    x0 = %s\n"
      "    u0 = %s\n"
      "\n"
      <%matrixA%>
      <%matrixB%>
      <%matrixC%>
      <%matrixD%>
      "    stateVars  = [<%getVarNamePython(vars.stateVars, "x0")%>]\n"
      "    inputVars  = [<%getVarNamePython(vars.inputVars, "u0")%>]\n"
      "    outputVars = [<%getVarNamePython(vars.outputVars, "y0")%>]\n"
      "\n"
      "    return (n, m, p, x0, u0, A, B, C, D, stateVars, inputVars, outputVars)\n";
    }
    const char *<%symbolName(modelNamePrefix,"linear_model_datarecovery_frame")%>()
    {
    }
    >>
  end match
end functionlinearmodelPython;

template getVarName(list<SimVar> simVars, String arrayName) "template getVarName
  Generates name for a varables."
::=
  simVars |> var hasindex arrindex fromindex 1 => (match var
    case SIMVAR(__) then
      <<"  Real '<%arrayName%>_<%crefStrNoUnderscore(name)%>' = <%arrayName%>[<%arrindex%>];\n">>
    end match) ;separator="\n"
end getVarName;

template getVarNameMatlab(list<SimVar> simVars, String arrayName) "template getVarName
  Generates name for a varables."
::=
  simVars |> var hasindex arrindex fromindex 1 => (match var
    case SIMVAR(__) then
      <<'<%crefStrMatlabSafe(name)%>'>>
    end match) ;separator=","
end getVarNameMatlab;

template getVarNamePython(list<SimVar> simVars, String arrayName) "template getVarName
  Generates name for a variables."
::=
  simVars |> var hasindex arrindex fromindex 0 => (match var
    case SIMVAR(__) then
      <<'<%crefStrMatlabSafe(name)%>'>>
    end match) ;separator=","
end getVarNamePython;

template getVarNameJulia(list<SimVar> simVars, String arrayName) "template getVarName
  Generates name for a varables."
::=
  simVars |> var hasindex arrindex fromindex 0 => (match var
    case SIMVAR(__) then
      <<\"<%crefStrMatlabSafe(name)%>\">>
    end match) ;separator=","
end getVarNameJulia;

template genMatrix(String name, String row, String col, Integer rowI, Integer colI) "template genMatrix
  Generates Matrix for linear model"
::=
  match rowI
  case 0 then
    <<"  parameter Real <%name%>[<%row%>, <%col%>] = zeros(<%row%>, <%col%>);%s\n\n">>
  case _ then
    match colI
    case 0 then
      <<"  parameter Real <%name%>[<%row%>, <%col%>] = zeros(<%row%>, <%col%>);%s\n\n">>
    case _ then
      <<"  parameter Real <%name%>[<%row%>, <%col%>] =\n\t[%s];\n\n">>
    end match
  end match
end genMatrix;

template genMatrixMatlab(String name, String row, String col, Integer rowI, Integer colI) "template genMatrixMatlab
  Generates Matrix for linear model in Matlab code"
::=
  match rowI
  case 0 then
    <<"  <%name%> = zeros(<%row%>, <%col%>);%s\n\n">>
  case _ then
    match colI
    case 0 then
      <<"  <%name%> = zeros(<%row%>, <%col%>);%s\n\n">>
    case _ then
      <<"  <%name%> =\t[%s];\n\n">>
    end match
  end match
end genMatrixMatlab;

template genMatrixPython(String name, String row, String col, Integer rowI, Integer colI) "template genMatrixPython
  Generates Matrix for linear model in python code"
::=
  match rowI
  case 0 then
    <<"    <%name%> = %s\n\n">>
  case _ then
    match colI
    case 0 then
      <<"    <%name%> = %s\n\n">>
    case _ then
      <<"    <%name%> = %s\n\n">>
    end match
  end match
end genMatrixPython;

template genMatrixJulia(String name, String row, String col, Integer rowI, Integer colI) "template genMatrixJulia
  Generates Matrix for linear model in Julia code"
::=
  match rowI
  case 0 then
    <<"  local <%name%> = zeros(<%row%>, <%col%>)%s\n">>
  case _ then
    match colI
    case 0 then
      <<"  local <%name%> = zeros(<%row%>, <%col%>)%s\n">>
    case _ then
      <<"  local <%name%> = [%s]\n\n">>
    end match
  end match
end genMatrixJulia;

template genVector(String name, String num, Integer numI, Integer flag) "template genVector
  Generates variables Vectors for linear model"
::=
  match flag
  case 0 then
    match numI
    case 0 then
      <<"  Real <%name%>[<%num%>];\n">>
    case _ then
      <<"  Real <%name%>[<%num%>](start=<%name%>0);\n">>
    end match
  case 1 then
    match numI
    case 0 then
      <<"  input Real <%name%>[<%num%>];\n">>
    case _ then
      <<"  input Real <%name%>[<%num%>](start=<%name%>0);\n">>
    end match
  case 2 then
    match numI
    case 0 then
      <<"  output Real <%name%>[<%num%>];\n">>
    case _ then
      <<"  output Real <%name%>[<%num%>];\n">>
    end match
  end match
end genVector;

template functionAnalyticJacobians(list<JacobianMatrix> JacobianMatrices,String modelNamePrefix, String fileNamePrefix) "template functionAnalyticJacobians
  This template generates source code for all given jacobians."
::=
  let initialjacMats = (JacobianMatrices |> JAC_MATRIX(columns=mat, seedVars=vars, matrixName=name, sparsity=sparsepattern, coloredCols=colorList, maxColorCols=maxColor, jacobianIndex=indexJacobian) =>
    initialAnalyticJacobians(mat, vars, name, sparsepattern, colorList, maxColor, modelNamePrefix, fileNamePrefix); separator="\n")
  let jacMats = (JacobianMatrices |> JAC_MATRIX(columns=mat, seedVars=vars, matrixName=name, partitionIndex=partIdx, crefsHT=crefsHT) =>
    generateMatrix(mat, vars, name, partIdx, crefsHT, modelNamePrefix) ;separator="\n")
  let jacGenericCalls = (JacobianMatrices |> jac as JAC_MATRIX() => genericCallBodies(jac.generic_loop_calls, createJacContext(jac.crefsHT)) ;separator="\n")

  <<
  <%jacMats%>

  <%initialjacMats%>

  <%jacGenericCalls%>
  >>
end functionAnalyticJacobians;

template initialAnalyticJacobians(list<JacobianColumn> jacobianColumn, list<SimVar> seedVars, String matrixname, SparsityPattern sparsepattern, list<list<Integer>> colorList, Integer maxColor, String modelNamePrefix, String fileNamePrefix)
"template initialAnalyticJacobians
  This template generates source code for functions that initialize the sparse-pattern for a single jacobian.
  This is a helper of template functionAnalyticJacobians"
::=
match sparsepattern
  case {} then
    <<
    int <%symbolName(modelNamePrefix,"initialAnalyticJacobian")%><%matrixname%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian)
    {
      TRACE_PUSH
      TRACE_POP
      jacobian->availability = JACOBIAN_NOT_AVAILABLE;
      return 1;
    }
    >>
  case _ then
    let &eachCrefParts = buffer ""
    let sp_size_index =  lengthListElements(unzipSecond(sparsepattern))
    let sizeleadindex = listLength(sparsepattern)
    let fileName = '<%fileNamePrefix%>_Jac<%matrixname%>.bin'
    let colorString = readSPColors(colorList, "jacobian->sparsePattern->colorCols")
    let availability = if SimCodeUtil.jacobianColumnsAreEmpty(jacobianColumn) then 'JACOBIAN_ONLY_SPARSITY' else 'JACOBIAN_AVAILABLE'
    let sizeRows = (jacobianColumn |> JAC_COLUMN(numberOfResultVars=nRows) => '<%nRows%>';separator="\n")
    let tmpvarsSize = (jacobianColumn |> JAC_COLUMN(columnVars=vars) => listLength(vars);separator="\n")
    let constantEqns = (jacobianColumn |> JAC_COLUMN(constantEqns=constantEqns) =>
      match constantEqns case {} then 'NULL' case _ then '<%symbolName(modelNamePrefix,"functionJac")%><%matrixname%>_constantEqns'
      ;separator="")
    let sizeCols = listLength(seedVars)
    <<
    OMC_DISABLE_OPT
    int <%symbolName(modelNamePrefix,"initialAnalyticJacobian")%><%matrixname%>(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian)
    {
      TRACE_PUSH
      size_t count;

      FILE* pFile = openSparsePatternFile(data, threadData, "<%fileName%>");

      initAnalyticJacobian(jacobian, <%sizeCols%>, <%sizeRows%>, <%tmpvarsSize%>, <%constantEqns%>, jacobian->sparsePattern);
      jacobian->sparsePattern = allocSparsePattern(<%sizeleadindex%>, <%sp_size_index%>, <%maxColor%>);
      jacobian->availability = <%availability%>;

      /* read lead index of compressed sparse column */
      count = omc_fread(jacobian->sparsePattern->leadindex, sizeof(unsigned int), <%sizeleadindex%>+1, pFile, FALSE);
      if (count != <%sizeleadindex%>+1) {
        throwStreamPrint(threadData, "Error while reading lead index list of sparsity pattern. Expected %d, got %zu", <%sizeleadindex%>+1, count);
      }

      /* read sparse index */
      count = omc_fread(jacobian->sparsePattern->index, sizeof(unsigned int), <%sp_size_index%>, pFile, FALSE);
      if (count != <%sp_size_index%>) {
        throwStreamPrint(threadData, "Error while reading row index list of sparsity pattern. Expected %d, got %zu", <%sizeleadindex%>+1, count);
      }

      /* write color array */
      <%colorString%>

      omc_fclose(pFile);

      TRACE_POP
      return 0;
    }
    >>
end match
end initialAnalyticJacobians;

template generateMatrix(list<JacobianColumn> jacobianColumn, list<SimVar> seedVars, String matrixname, Integer partIdx, Option<HashTableCrefSimVar.HashTable> jacHT, String modelNamePrefix)
  "This template generates source code for a single jacobian in dense format and sparse format.
  This is a helper of template functionAnalyticJacobians"
::=
  let nRows = (jacobianColumn |> JAC_COLUMN(numberOfResultVars=nRows) => '<%nRows%>')
  match nRows
  case "0" then
    <<
    int <%symbolName(modelNamePrefix,"functionJac")%><%matrixname%>_column(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian, ANALYTIC_JACOBIAN *parentJacobian)
    {
      TRACE_PUSH
      TRACE_POP
      return 0;
    }
    >>
  case _ then
    match seedVars
     case {} then
        <<
        int <%symbolName(modelNamePrefix,"functionJac")%><%matrixname%>_column(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian, ANALYTIC_JACOBIAN *parentJacobian)
        {
          TRACE_PUSH
          TRACE_POP
          return 0;
        }
        >>
      case _ then
        let jacMats =
        (jacobianColumn |> JAC_COLUMN(columnEqns=eqs, constantEqns=constantEqns) =>
          functionJac(eqs, constantEqns, partIdx, matrixname, jacHT, modelNamePrefix)
          ;separator="\n")
        let indexColumn = (jacobianColumn |> JAC_COLUMN(numberOfResultVars=nRows) =>
          nRows
          ;separator="\n")
        <<
        <%jacMats%>
        >>
     end match
  end match
end generateMatrix;

template generateConstantEqns(list<SimEqSystem> constantEqns, String matrixName, String modelNamePrefix)
::=
    <<
    OMC_DISABLE_OPT
    int <%symbolName(modelNamePrefix,"functionJac")%><%matrixName%>_constantEqns(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian, ANALYTIC_JACOBIAN *parentJacobian)
    {
      TRACE_PUSH

      int index = <%symbolName(modelNamePrefix,"INDEX_JAC_")%><%matrixName%>;
      <%(constantEqns |> eq => equation_callJacobian(eq, modelNamePrefix); separator="")%>

      TRACE_POP
      return 0;
    }
    >>
end generateConstantEqns;

template functionJac(list<SimEqSystem> jacEquations, list<SimEqSystem> constantEqns, Integer base_idx, String matrixName, Option<HashTableCrefSimVar.HashTable> jacHT, String modelNamePrefix)
  "This template generates functions for each column of a single jacobian.
   This is a helper of generateMatrix."
::=
  let constantEqns2 = generateConstantEqns(constantEqns, matrixName, modelNamePrefix)
  <<
  /* constant equations */
  <%(constantEqns |> eq hasindex sub_idx =>
    equation_impl(base_idx, sub_idx, eq, createJacContext(jacHT), modelNamePrefix, false); separator="\n")%>
  /* dynamic equations */
  <%(jacEquations |> eq hasindex sub_idx =>
    equation_impl(base_idx, sub_idx, eq, createJacContext(jacHT), modelNamePrefix, false); separator="\n")%>

  <%constantEqns2%>

  int <%symbolName(modelNamePrefix,"functionJac")%><%matrixName%>_column(DATA* data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian, ANALYTIC_JACOBIAN *parentJacobian)
  {
    TRACE_PUSH

    int index = <%symbolName(modelNamePrefix,"INDEX_JAC_")%><%matrixName%>;
    <%(jacEquations |> eq => equation_callJacobian(eq, modelNamePrefix); separator="")%>
    TRACE_POP
    return 0;
  }
  >>
end functionJac;

// function for sparsity pattern generation
template genSPCRSPtr(Integer sizeColPtr, SparsityPattern sparsepattern, String constArrayName)
"This template generates colPtr of the CRS format"
::=
  let colPtrindex = (sparsepattern |> (i, indexes) =>
  <<
  <%listLength(indexes)%>
  >>
  ;separator=",")
  <<
  const int <%constArrayName%>[1+<%sizeColPtr%>] = {0,<%colPtrindex%>};
  >>
end genSPCRSPtr;

template genSPCRSRows(Integer nonZeroElems, SparsityPattern sparsepattern, String constArrayName)
"This template generates row of the CRS format"
::=
  let rowsIndex = ( sparsepattern |> (i, indexes) hasindex index0 =>
    ( indexes |> indexrow =>
    <<
    <%indexrow%>
    >>
    ;separator=",")
  ;separator=",")
  <<
  const int <%constArrayName%>[<%nonZeroElems%>] = {<%rowsIndex%>};
  >>
end genSPCRSRows;

template genSPColors(list<list<Integer>> colorList, String arrayName)
"This template generates row of the CRS format"
::=
  let colorArray = (colorList |> (indices) hasindex index0 =>
    let length = '<%listLength(indices)%>'
    let index = '<%intAdd(index0,1)%>'
    let ind_name = 'indices_<%index%>'
  <<
  /* color <%index%> with <%length%> columns */
  const int <%ind_name%>[<%length%>] = {<%(indices |> i_index =>
    '<%i_index%>' ;separator=", ")%>};
  for(i=0; i<<%length%>; i++)
    <%arrayName%>[<%ind_name%>[i]] = <%index%>;
  >>;separator="\n\n")
  <<
  <%colorArray%>
  >>
end genSPColors;

template readSPColors(list<list<Integer>> colorList, String arrayName)
"This template generates row of the CRS format"
::=
  let colorArray = (colorList |> (indices) hasindex index0 =>
    let length = '<%listLength(indices)%>'
    let index = '<%intAdd(index0,1)%>'
    let ind_name = 'indices_<%index%>'
  <<
  /* color <%index%> with <%length%> columns */
  readSparsePatternColor(threadData, pFile, <%arrayName%>, <%index%>, <%length%>);
  >>;separator="\n")
  <<
  <%colorArray%>
  >>
end readSPColors;

template equation_arrayFormat(SimEqSystem eq, String name, Context context, Integer arrayIndex, Text &eqArray, Text &eqfuncs, String modelNamePrefix, Boolean init)
 "Generates an equation.
  This template should not be used for a SES_RESIDUAL.
  Residual equations are handled differently."
::=
  match eq
  case e as SES_ALGORITHM(statements={})
  then ""
  else
  (
  let ix = equationIndex(eq) /*System.tmpTickIndex(10)*/
  let &tmp = buffer ""
  let &varD = buffer ""
  let &tempeqns = buffer ""
  let &OMC_DISABLE_OPT = buffer ""
  let() = System.tmpTickResetIndex(0,1) /* Boxed array indices */
  let disc = match context
  case SIMULATION_CONTEXT(genDiscrete=true) then 1
  else 0
  let x = match eq
  case e as SES_SIMPLE_ASSIGN(__)
  case e as SES_SIMPLE_ASSIGN_CONSTRAINTS(__)
    then equationSimpleAssign(e, context, &varD, &tempeqns)
  case e as SES_ARRAY_CALL_ASSIGN(__)
    then equationArrayCallAssign(e, context, &varD, &tempeqns)
  case e as SES_GENERIC_ASSIGN(__)
    then equationGenericAssign(e, context, &varD, &tempeqns, modelNamePrefix)
  case e as SES_ENTWINED_ASSIGN(__)
    then equationEntwinedAssign(e, context, &varD, &tempeqns, modelNamePrefix)
  case e as SES_IFEQUATION(__)
    then equationIfEquationAssign(e, context, &varD, &tempeqns, modelNamePrefix, init)
  case e as SES_ALGORITHM(__)
  case e as SES_INVERSE_ALGORITHM(__)
    then equationAlgorithm(e, context, &varD, &tempeqns)
  case e as SES_LINEAR(__)
    then
    let &OMC_DISABLE_OPT += 'OMC_DISABLE_OPT<%\n%>'
    equationLinear(e, context, &varD)
  // no dynamic tearing
  case e as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__), alternativeTearing=NONE()) then
    let &tempeqns += (nls.eqs |> eq => 'void <%symbolName(modelNamePrefix,"eqFunction")%>_<%equationIndex(eq)%>(DATA*,threadData_t*);' ; separator = "\n")
  equationNonlinear(e, context, modelNamePrefix, init)
  // dynamic tearing
  case e as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__), alternativeTearing = SOME(at as NONLINEARSYSTEM(__))) then
    let &tempeqns += (nls.eqs |> eq => 'void <%symbolName(modelNamePrefix,"eqFunction")%>_<%equationIndex(eq)%>(DATA*,threadData_t*);' ; separator = "\n")
    let &tempeqns += '<%\n%>'
    let &tempeqns += (at.eqs |> eq => 'void <%symbolName(modelNamePrefix,"eqFunction")%>_<%equationIndex(eq)%>(DATA*,threadData_t*);' ; separator = "\n")
  equationNonlinear(e, context, modelNamePrefix, init)
  case e as SES_WHEN(__)
    then equationWhen(e, context, &varD, &tempeqns)
  case e as SES_RESIDUAL(__)
    then "NOT IMPLEMENTED EQUATION SES_RESIDUAL"
  case e as SES_FOR_RESIDUAL(__)
    then "NOT IMPLEMENTED EQUATION SES_FOR_RESIDUAL"
  case e as SES_GENERIC_RESIDUAL(__)
    then "NOT IMPLEMENTED EQUATION SES_GENERIC_RESIDUAL"
  case e as SES_MIXED(__)
    then equationMixed(e, context, &eqfuncs, modelNamePrefix, init)
  else
    error(sourceInfo(), "NOT IMPLEMENTED EQUATION equation_")

  let &eqArray += '<%symbolName(modelNamePrefix,"eqFunction")%>_<%ix%>, <%\n%>'
  let &varD += addRootsTempArray()
  let &eqfuncs +=
  <<

  <%tempeqns%>
  /*
   <%dumpEqs(fill(eq,1))%>
   */
  <%OMC_DISABLE_OPT%>void <%symbolName(modelNamePrefix,"eqFunction")%>_<%ix%>(DATA *data, threadData_t *threadData)
  {
    TRACE_PUSH
    const int equationIndexes[2] = {1,<%ix%>};
    <%&varD%>
    <%x%>
    TRACE_POP
  }
  >>
  <<
  // <%symbolName(modelNamePrefix,"eqFunction")%>_<%ix%>(data, threadData);
  function<%name%>_systems[<%arrayIndex%>](data, threadData);
  >>
  )
end equation_arrayFormat;

template equation_impl(Integer base_idx, Integer sub_idx, SimEqSystem eq, Context context, String modelNamePrefix, Boolean init)
 "Generates an equation.
  This template should not be used for a SES_RESIDUAL.
  Residual equations are handled differently."
::=
  <<
    <%equation_impl2(base_idx, sub_idx, eq, context, modelNamePrefix, false, false, init)%>
  >>
end equation_impl;

template equation_impl_options(Integer base_idx, Integer sub_idx, SimEqSystem eq, Context context, String modelNamePrefix, Boolean static, Boolean noOpt, Boolean init)
 "Generates an equation.
  This template should not be used for a SES_RESIDUAL.
  Residual equations are handled differently."
::=
  equation_impl2(base_idx, sub_idx, eq, context, modelNamePrefix, static, noOpt, init)
end equation_impl_options;

template equation_impl2(Integer base_idx, Integer sub_idx, SimEqSystem eq, Context context, String modelNamePrefix, Boolean static, Boolean noOpt, Boolean init)
 "Generates an equation.
  This template should not be used for a SES_RESIDUAL.
  Residual equations are handled differently."
::=
  let OMC_NO_OPT = if noOpt then 'OMC_DISABLE_OPT<%\n%>' else (match eq case SES_LINEAR(__) then 'OMC_DISABLE_OPT<%\n%>')
  match eq

    case SES_ALIAS(__) then 'extern void <%symbolName(modelNamePrefix,"eqFunction")%>_<%aliasOf%>(DATA *data, threadData_t *threadData);<%\n%>'
    case e as SES_ALGORITHM(statements={}) then ""
    else
    (
    let ix = equationIndex(eq) /*System.tmpTickIndex(10)*/
    let ix2 = match eq
        case e as SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing = SOME(at as LINEARSYSTEM(__)))
        case e as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__), alternativeTearing = SOME(at as NONLINEARSYSTEM(__)))
        then equationIndexAlternativeTearing(eq)
        else  ""
    let &tmp = buffer ""
    let &varD = buffer ""
    let &tempeqns = buffer ""
    let &tempeqns2 = buffer ""
    let() = System.tmpTickResetIndex(0,1) /* Boxed array indices */
    let disc = match context case SIMULATION_CONTEXT(genDiscrete=true) then 1 else 0
    let x = match eq

        case e as SES_SIMPLE_ASSIGN(__)
        case e as SES_SIMPLE_ASSIGN_CONSTRAINTS(__)
        then equationSimpleAssign(e, context, &varD, &tempeqns)

        case e as SES_ARRAY_CALL_ASSIGN(__)
        then equationArrayCallAssign(e, context, &varD, &tempeqns)

        case e as SES_GENERIC_ASSIGN(__)
        then equationGenericAssign(e, context, &varD, &tempeqns, modelNamePrefix)

        case e as SES_ENTWINED_ASSIGN(__)
        then equationEntwinedAssign(e, context, &varD, &tempeqns, modelNamePrefix)

        case e as SES_IFEQUATION(__)
        then equationIfEquationAssign(e, context, &varD, &tempeqns, modelNamePrefix, init)

        case e as SES_ALGORITHM(__)
        then equationAlgorithm(e, context, &varD, &tempeqns)

        case e as SES_INVERSE_ALGORITHM(__)
        then equationAlgorithm(e, context, &varD, &tempeqns)

        case e as SES_LINEAR(__)
        then equationLinear(e, context, &varD)

        case e as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__))
        then
            let &tempeqns += (nls.eqs |> eq => 'void <%symbolName(modelNamePrefix,"eqFunction")%>_<%equationIndex(eq)%>(DATA*, threadData_t*);' ; separator = "\n")
          equationNonlinear(e, context, modelNamePrefix, init)

        case e as SES_WHEN(__)
        then equationWhen(e, context, &varD, &tempeqns)

        case e as SES_RESIDUAL(__)
        then "NOT IMPLEMENTED EQUATION SES_RESIDUAL"

        case e as SES_FOR_RESIDUAL(__)
        then "NOT IMPLEMENTED EQUATION SES_FOR_RESIDUAL"

        case e as SES_GENERIC_RESIDUAL(__)
        then "NOT IMPLEMENTED EQUATION SES_GENERIC_RESIDUAL"

        case e as SES_MIXED(__)
        then
            let &eqs = buffer ""
            let res = equationMixed(e, context, &eqs, modelNamePrefix, init)
            eqs + res

        case e as SES_FOR_LOOP(__)
        then equationForLoop(e, context, &varD, &tempeqns)

        else "NOT IMPLEMENTED EQUATION equation_"

    let x2 = match eq
        case e as SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing = SOME(at as LINEARSYSTEM(__)))
        then equationLinearAlternativeTearing(e, context, &varD)

        case e as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__), alternativeTearing = SOME(at as NONLINEARSYSTEM(__)))
        then
            let &tempeqns2 += (at.eqs |> eq => 'void <%symbolName(modelNamePrefix,"eqFunction")%>_<%equationIndex(eq)%>(DATA*,threadData_t*);' ; separator = "\n")
          equationNonlinearAlternativeTearing(e, context, modelNamePrefix, init)
        else ""

    let &varD += addRootsTempArray()
    let baseClockIndex_ = if intLt(base_idx, 0) then '' else 'const int baseClockIndex = <%base_idx%>;'
    let subClockIndex_ = if intLt(sub_idx, 0) then '' else 'const int subClockIndex = <%sub_idx%>;'

    match eq
        // dynamic tearing
        case e as SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing = SOME(at as LINEARSYSTEM(__)))
        case e as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__), alternativeTearing = SOME(at as NONLINEARSYSTEM(__))) then
        <<
        <%tempeqns%>
        /*
        <%dumpEqs(fill(eq,1))%>
        */
        <%OMC_NO_OPT%><% if static then "static "%>int <%symbolName(modelNamePrefix,"eqFunction")%>_<%ix%>(DATA *data, threadData_t *threadData)
        {
          TRACE_PUSH
          <%baseClockIndex_%>
          <%subClockIndex_%>
          const int equationIndexes[2] = {1,<%ix%>};
          <%&varD%>
          <%x%>
          TRACE_POP
        }

        <%tempeqns2%>
        /*
        <%dumpEqsAlternativeTearing(fill(eq,1))%>
        */
        <%OMC_NO_OPT%><% if static then "static "%>void <%symbolName(modelNamePrefix,"eqFunction")%>_<%ix2%>(DATA *data, threadData_t *threadData)
        {
          TRACE_PUSH
          <%baseClockIndex_%>
          <%subClockIndex_%>
          const int equationIndexes[2] = {1,<%ix2%>};
          <%&varD%>
          <%x2%>
          TRACE_POP
        }
        >>

        // no dynamic tearing
        else
        match context
        case JACOBIAN_CONTEXT()
        then
        <<
        <%tempeqns%>
		=========
        /*
        <%dumpEqs(fill(eq,1))%>
        */
        <%OMC_NO_OPT%><% if static then "static "%>void <%symbolName(modelNamePrefix,"eqFunction")%>_<%ix%>(DATA *data, threadData_t *threadData, ANALYTIC_JACOBIAN *jacobian, ANALYTIC_JACOBIAN *parentJacobian)
        {
          TRACE_PUSH
          <%baseClockIndex_%>
          <%subClockIndex_%>
          const int equationIndexes[2] = {1,<%ix%>};
          <%&varD%>
          <%x%>
          TRACE_POP
        }
        >>
        else
        <<
		
		<%dumpEqs(fill(eq,1))%>
		>>
  )
end equation_impl2;

template equation_call_context(SimEqSystem eq, String modelNamePrefix, Context context)
  "Generates either a normal or jacobian equation depending on context.
   ToDo: add other cases?"
::=
  match context
  case JACOBIAN_CONTEXT() then equation_callJacobian(eq, modelNamePrefix)
  else equation_call(eq, modelNamePrefix)
  end match
end equation_call_context;

template equation_call(SimEqSystem eq, String modelNamePrefix)
 "Generates an equation.
  This template should not be used for a SES_RESIDUAL.
  Residual equations are handled differently."
::=
<<
>>
end equation_call;

template equation_callJacobian(SimEqSystem eq, String modelNamePrefix)
 "Generates the equation calls for jacobians fucntion."
::=
  match eq
  case e as SES_ALGORITHM(statements={})
  then ""
  else
  (
  let ix = match eq
  case e as SES_LINEAR(alternativeTearing = SOME(LINEARSYSTEM))
  case e as SES_NONLINEAR(alternativeTearing = SOME(NONLINEARSYSTEM)) then
    equationIndexAlternativeTearing(eq)
  else
    equationIndex(eq)
  end match
  <<
  <% if profileAll() then 'SIM_PROF_TICK_EQ(<%ix%>);' %>
  <%symbolName(modelNamePrefix,"eqFunction")%>_<%ix%>(data, threadData, jacobian, parentJacobian);
  <% if profileAll() then 'SIM_PROF_ACC_EQ(<%ix%>);' %>
  >>
  )
end equation_callJacobian;


template equationForward_(SimEqSystem eq, Context context, String modelNamePrefixStr)
 "Generates an equation.
  This template should not be used for a SES_RESIDUAL.
  Residual equations are handled differently."
::=
 match eq
  case e as SES_ALGORITHM(statements={})
  then ""
  else
  let ix = match eq
  case e as SES_LINEAR(alternativeTearing = SOME(LINEARSYSTEM))
  case e as SES_NONLINEAR(alternativeTearing = SOME(NONLINEARSYSTEM)) then
    equationIndexAlternativeTearing(eq)
  else
    equationIndex(eq)
  end match
  <<
  extern void <%symbolName(modelNamePrefixStr,"eqFunction")%>_<%ix%>(DATA* data, threadData_t *threadData);
  >>
end equationForward_;

template equationNames_(SimEqSystem eq, Context context, String modelNamePrefixStr)
 "Generates an equation.
  This template should not be used for a SES_RESIDUAL.
  Residual equations are handled differently."
::=
 match eq
  case e as SES_ALGORITHM(statements={})
  then ""
  else
  let ix = match eq
  case e as SES_LINEAR(alternativeTearing = SOME(LINEARSYSTEM))
  case e as SES_NONLINEAR(alternativeTearing = SOME(NONLINEARSYSTEM)) then
    equationIndexAlternativeTearing(eq)
  else
    equationIndex(eq)
  end match
  let simEqAttrEval = match context case(DAE_MODE_CONTEXT()) then '<%simEqAttrEval(eq)%>'
  let simEqAttrIsDiscreteKind = match context case(DAE_MODE_CONTEXT()) then '<%simEqAttrIsDiscreteKind(eq)%>'
  <<
  <% match simEqAttrEval case "" then '' else '<%simEqAttrEval%>' %>
  <% match simEqAttrEval case "" then '{' else 'if ((evalStages & currentEvalStage) && !((currentEvalStage!=EVAL_DISCRETE)?(<%simEqAttrIsDiscreteKind%>):0)) {' %>
    <% if profileAll() then 'SIM_PROF_TICK_EQ(<%ix%>);' %>
    <%symbolName(modelNamePrefixStr,"eqFunction")%>_<%ix%>(data, threadData);
    <% if profileAll() then 'SIM_PROF_ACC_EQ(<%ix%>);' %>
    threadData->lastEquationSolved = <%ix%>;
  }
  >>
end equationNames_;

template equationSimpleAssign(SimEqSystem eq, Context context,
                              Text &varDecls, Text &auxFunction)
 "Generates an equation that is just a simple assignment."
::=
match eq
case SES_SIMPLE_ASSIGN(exp=CALL(path=IDENT(name="fail")))
case SES_SIMPLE_ASSIGN_CONSTRAINTS(exp=CALL(path=IDENT(name="fail"))) then
  '<%generateThrow()%><%\n%>'
case SES_SIMPLE_ASSIGN(__)
case SES_SIMPLE_ASSIGN_CONSTRAINTS(__) then
  let &sub = buffer ""
  let &preExp = buffer ""
  let expPart = daeExp(exp, context, &preExp, &varDecls, &auxFunction)
  let postExp = if isStartCref(cref) then
    <<
    <%cref(popCref(cref), &sub)%> = <%cref(cref, &sub)%>;
    infoStreamPrint(LOG_INIT_V, 0, "updated start value: %s(start=<%crefToPrintfArg(popCref(cref))%>)", <%crefVarInfo(popCref(cref))%>.name, (<%crefType(popCref(cref))%>) <%cref(popCref(cref), &sub)%>);
    >>
  <<
  <%modelicaLine(eqInfo(eq))%>
  <%preExp%>
  <%contextCref(cref, context, &preExp, &varDecls, auxFunction, &sub)%> = <%expPart%>;
    <%postExp%>
  <%endModelicaLine()%>
  >>
end equationSimpleAssign;

template equationForLoop(SimEqSystem eq, Context context, Text &varDecls, Text &auxFunction)
 "Generates an equation that is a for-loop."
::=
match eq
case SES_FOR_LOOP(__) then
  let &preExp = buffer ""
  let expPart = daeExp(exp, context, &preExp, &varDecls, &auxFunction)
  let crefPart = daeExp(crefExp(cref), context, &preExp, &varDecls, &auxFunction)
  //let bodyStr = daeExpIteratedCref(body)
  let start = dumpExp(startIt,"\"")
  let stop = dumpExp(endIt,"\"")
  let iterVar = daeExp(iter, context, &preExp, &varDecls, &auxFunction)
  <<
  <%modelicaLine(eqInfo(eq))%>
  modelica_integer  $P<%dumpExp(iter,"\"")%> = 0; // the iterator
  // the for-equation
  for($P<%dumpExp(iter,"\"")%> = <%start%>; $P<%dumpExp(iter,"\"")%> != <%stop%>+1; $P<%dumpExp(iter,"\"")%>++)
  {
    <%crefPart%> += <%expPart%>;
  }
  <%endModelicaLine()%>
  >>
end equationForLoop;


template equationArrayCallAssign(SimEqSystem eq, Context context,
                                 Text &varDecls, Text &auxFunction)
 "Generates equation on form 'cref_array = call(...)'."
::=
<<
<%modelicaLine(eqInfo(eq))%>
<%match eq

case eqn as SES_ARRAY_CALL_ASSIGN(lhs=lhs as CREF(__)) then
  let &preExp = buffer ""
  let expPart = daeExp(exp, context, &preExp, &varDecls, &auxFunction)
  if crefSubIsScalar(lhs.componentRef) then
    let lhsstr = daeExpCrefLhs(lhs, context, &preExp, &varDecls, &auxFunction, false)
    match expTypeFromExpShort(eqn.exp)
      case "boolean" then
      <<
      <%preExp%>
      boolean_array_copy_data(<%expPart%>, <%lhsstr%>);
      >>
    case "integer" then
      <<
      <%preExp%>
      integer_array_copy_data(<%expPart%>, <%lhsstr%>);
      >>
    case "real" then
      <<
      <%preExp%>
      real_array_copy_data(<%expPart%>, <%lhsstr%>);
      >>
    case "string" then
      <<
      <%preExp%>
      string_array_copy_data(<%expPart%>, <%lhsstr%>);
      >>
    else error(sourceInfo(), 'No runtime support for this sort of array call: <%dumpExp(eqn.exp,"\"")%>')
  else
    let assign = algStmtAssignArrWithRhsExpStr(lhs, expPart, context, &preExp, &varDecls, &auxFunction)
    <<
    <%preExp%>
    <%assign%>
    >>
%>
<%endModelicaLine()%>
>>
end equationArrayCallAssign;

template equationGenericAssign(SimEqSystem eq, Context context,
                                 Text &varDecls, Text &auxFunction, String modelNamePrefix)
 "Generate a call for a generic for-loop structure with an index-list."
::=
<<
<%modelicaLine(eqInfo(eq))%>
<%match eq

case eqn as SES_GENERIC_ASSIGN() then
  let idx_len = listLength(scal_indices)
  let jac = match context case JACOBIAN_CONTEXT() then ", jacobian" else ""
  <<
  const int idx_lst[<%idx_len%>] = {<%(scal_indices |> idx => '<%idx%>';separator=", ")%>};
  for(int i=0; i<<%idx_len%>; i++)
    genericCall_<%call_index%>(data, threadData<%jac%>, idx_lst[i]); /*<%symbolName(modelNamePrefix,"genericCall")%>*/
  >>
%>
<%endModelicaLine()%>
>>
end equationGenericAssign;

template equationEntwinedAssign(SimEqSystem eq, Context context,
                                 Text &varDecls, Text &auxFunction, String modelNamePrefix)
 "Generate a call for entwined generic for-loop structures with an index-lists and a call order."

::=
<<
<%modelicaLine(eqInfo(eq))%>
<%match eq

case eqn as SES_ENTWINED_ASSIGN() then
  let call_num = listLength(single_calls)
  let call_order_len = listLength(call_order)
  <<
  int call_indices[<%call_num%>] = {<%(single_calls |> call => '0'; separator=", ")%>};
  const int call_order[<%call_order_len%>] = {<%(call_order |> idx => '<%idx%>'; separator=", ")%>};
  <%(single_calls |> call hasindex i0 => entwinedSingleCallIndices(call, context, &varDecls, &auxFunction, modelNamePrefix); separator="\n")%>
  for(int i=0; i<<%call_order_len%>; i++)
  {
    switch(call_order[i])
    {
    <%(single_calls |> call hasindex i0 => entwinedSingleCall(call, i0, context, &varDecls, &auxFunction, modelNamePrefix); separator="\n")%>
      default:
        throwStreamPrint(NULL, "Call index %d at pos %d unknown for: <%modelicaLine(eqInfo(eq))%>", call_order[i], i);
        break;
    }
  }
  >>
%>
<%endModelicaLine()%>
>>
end equationEntwinedAssign;

template entwinedSingleCallIndices(SimEqSystem eq, Context context,
                                 Text &varDecls, Text &auxFunction, String modelNamePrefix)
::=
<<
<%match eq
case eqn as SES_GENERIC_ASSIGN() then
  let idx_len = listLength(scal_indices)
  <<
  const int idx_lst_<%call_index%>[<%idx_len%>] = {<%(scal_indices |> idx => '<%idx%>';separator=", ")%>};
  >>
%>
>>
end entwinedSingleCallIndices;

template entwinedSingleCall(SimEqSystem eq, Integer i0, Context context,
                                 Text &varDecls, Text &auxFunction, String modelNamePrefix)
::=
<<
<%match eq
case eqn as SES_GENERIC_ASSIGN() then
  let jac = match context case JACOBIAN_CONTEXT() then ", jacobian" else ""
  <<
    case <%call_index%>:
      genericCall_<%call_index%>(data, threadData<%jac%>, idx_lst_<%call_index%>[call_indices[<%i0%>]]);
      call_indices[<%i0%>]++;
      break;
  >>
%>
>>
end entwinedSingleCall;

template equationAlgorithm(SimEqSystem eq, Context context, Text &varDecls, Text &auxFunction)
 "Generates an equation that is an algorithm."
::=
match eq
/* SES_INVERSE_ALGORITHM which is used by the non-linear solver */
case alg as SES_INVERSE_ALGORITHM(insideNonLinearSystem=true)
case SES_ALGORITHM(__) then
  (statements |> stmt =>
    algStatement(stmt, context, &varDecls, &auxFunction)
  ;separator="\n")
/* Generates an equation that is an inverse algorithm
  without continuous variables, discrete variables are
  handled by the event iteration */
case alg as SES_INVERSE_ALGORITHM(__) then
  let &sub = buffer ""
  let backupKnown = (alg.knownOutputCrefs |> cr hasindex i0 =>
    let &varDecls += '<%crefType(cr)%> OLD_<%i0%>;<%\n%>'
       'OLD_<%i0%> = <%cref(cr, &sub)%>;'
      ;separator="\n")
  let stmts = (statements |> stmt =>
    algStatement(stmt, context, &varDecls, &auxFunction)
  ;separator="\n")
  let restoreKnownVars = (alg.knownOutputCrefs |> cr hasindex i0 => '<%cref(cr, &sub)%> = OLD_<%i0%>;' ;separator="\n")
  <<
  /* backup outputs of the algorithm */
  <%backupKnown%>
  /* algrithm it self */
  <%stmts%>
  /* restore outputs of the algorithm */
  <%restoreKnownVars%>
  >>
end equationAlgorithm;

template equationLinear(SimEqSystem eq, Context context, Text &varDecls)
 "Generates a linear equation system."
::=
match eq
case e as SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing = at) then
  let returnval = match at case at as SOME(__) then 'return 1;' case at as NONE() then ''
  let returnval2 = match at case at as SOME(__) then 'return 0;' case at as NONE() then ''
  let auxFunctions = ""
  <<
  /* Linear equation system */
  int retValue;
  double aux_x[<%listLength(ls.vars)%>] = { <%ls.vars |> SIMVAR(__) hasindex i0 => '<%contextCrefOld(name, context, auxFunctions, 1)%>' ;separator=","%> };
  if(ACTIVE_STREAM(LOG_DT))
  {
    infoStreamPrint(LOG_DT, 1, "Solving linear system <%ls.index%> (STRICT TEARING SET if tearing enabled) at time = %18.10e", data->localData[0]->timeValue);
    messageClose(LOG_DT);
  }
  <% if profileSome() then 'SIM_PROF_TICK_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%ls.index%>).profileBlockIndex);' %>
  <% if ls.partOfJac then
     'data->simulationInfo->linearSystemData[<%ls.indexLinearSystem%>].parDynamicData[omc_get_thread_num()].parentJacobian = jacobian;'
  %>

  retValue = solve_linear_system(data, threadData, <%ls.indexLinearSystem%>, &aux_x[0]);

  /* check if solution process was successful */
  if (retValue > 0){
    const int indexes[2] = {1,<%ls.index%>};
    throwStreamPrintWithEquationIndexes(threadData, omc_dummyFileInfo, indexes, "Solving linear system <%ls.index%> failed at time=%.15g.\nFor more information please use -lv LOG_LS.", data->localData[0]->timeValue);
    <%returnval2%>
  }
  /* write solution */
  <%ls.vars |> SIMVAR(__) hasindex i0 => '<%contextCrefNoPrevExp(name, context, auxFunctions)%> = aux_x[<%i0%>];' ;separator="\n"%>
  <% if profileSome() then 'SIM_PROF_ACC_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%ls.index%>).profileBlockIndex);' %>

  <%returnval%>
  >>
end equationLinear;


template equationLinearAlternativeTearing(SimEqSystem eq, Context context, Text &varDecls)
 "Generates a linear equation system for the alternative tearing set."
::=
match eq
case e as SES_LINEAR(lSystem=ls as LINEARSYSTEM(__), alternativeTearing = SOME(at as LINEARSYSTEM(__))) then
  let auxFunctions = ""
  <<
  /* Linear equation system */
  int retValue;

  if(ACTIVE_STREAM(LOG_DT))
  {
    infoStreamPrint(LOG_DT, 1, "Solving linear system <%at.index%> (CASUAL TEARING SET, strict: <%ls.index%>) at time = %18.10e", data->localData[0]->timeValue);
    messageClose(LOG_DT);
  }
  <% if profileSome() then 'SIM_PROF_TICK_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%at.index%>).profileBlockIndex);' %>
  if (data->simulationInfo->linearSystemData[<%at.indexLinearSystem%>].checkConstraints(data, threadData) == 1)
  {
    double aux_x[<%listLength(at.vars)%>] = { <%at.vars |> SIMVAR(__) hasindex i0 => '<%contextCrefNoPrevExp(name, context, auxFunctions)%>' ;separator=","%> };
    retValue = solve_linear_system(data, threadData, <%at.indexLinearSystem%>, &aux_x[0]);
    /* The casual tearing set found a solution */
    if (retValue == 0){
      /* write solution */
      <%at.vars |> SIMVAR(__) hasindex i0 => '<%contextCrefNoPrevExp(name, context, auxFunctions)%> = aux_x[<%i0%>];' ;separator="\n"%>
      <% if profileSome() then 'SIM_PROF_ACC_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%at.index%>).profileBlockIndex);' %>
    }
  }
  else
  {
    if(ACTIVE_STREAM(LOG_DT))
    {
      infoStreamPrint(LOG_DT, 1, "Constraints of the casual tearing set are violated! Now the strict tearing set is used.");
      messageClose(LOG_DT);
    }
    /* Global constraints are violated. Use the strict tearing set now. */
    data->simulationInfo->linearSystemData[<%at.indexLinearSystem%>].strictTearingFunctionCall(data, threadData);
  }
  >>
end equationLinearAlternativeTearing;


template equationMixed(SimEqSystem eq, Context context, Text &tmp, String modelNamePrefixStr, Boolean init)
 "Generates a mixed equation system."
::=
match eq
case eqn as SES_MIXED(__) then
  let &sub = buffer ""
  let &tmp += equation_impl(-1, -1, cont, context, modelNamePrefixStr, init)
  let numDiscVarsStr = listLength(discVars)
  <<
  /* Continuous equation part */
  <% if profileSome() then 'SIM_PROF_TICK_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%index%>).profileBlockIndex);' %>
  <%discVars |> SIMVAR(__) hasindex i0 => 'data->simulationInfo->mixedSystemData[<%eqn.indexMixedSystem%>].iterationVarsPtr[<%i0%>] = (modelica_boolean*)&<%cref(name, &sub)%>;' ;separator="\n"%>;
  <%discVars |> SIMVAR(__) hasindex i0 => 'data->simulationInfo->mixedSystemData[<%eqn.indexMixedSystem%>].iterationPreVarsPtr[<%i0%>] = (modelica_boolean*)&<%crefPre(name)%>;' ;separator="\n"%>;
  solve_mixed_system(data, <%indexMixedSystem%>);
  <% if profileSome() then 'SIM_PROF_ACC_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%index%>).profileBlockIndex);' %>
  >>
end equationMixed;


template equationNonlinear(SimEqSystem eq, Context context, String modelNamePrefix, Boolean init)
 "Generates a non linear equation system."
::=
  match eq
    case eq as SES_NONLINEAR(nlSystem=nls as NONLINEARSYSTEM(__), alternativeTearing = at) then
      let size = listLength(nls.crefs)
      let &tmp = buffer ""
      let innerBody = (nls.eqs |> eq2 =>
         functionExtraResidualsPreBody(eq2, &tmp, modelNamePrefix)
       ;separator="\n")
      let nonlinindx = nls.indexNonLinearSystem
      let returnval = match at case at as SOME(__) then 'return 1;' case at as NONE() then ''
      let returnval2 = match at case at as SOME(__) then 'return 0;' case at as NONE() then ''
      <<
      int retValue;
      if(ACTIVE_STREAM(LOG_DT))
      {
        infoStreamPrint(LOG_DT, 1, "Solving nonlinear system <%nls.index%> (STRICT TEARING SET if tearing enabled) at time = %18.10e", data->localData[0]->timeValue);
        messageClose(LOG_DT);
      }
      <% if profileSome() then
      <<
      SIM_PROF_TICK_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%nls.index%>).profileBlockIndex);
      SIM_PROF_ADD_NCALL_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%nls.index%>).profileBlockIndex,-1);
      >>
      %>
      /* get old value */
      <%nls.crefs |> name hasindex i0 =>
        let &sub = buffer ""
        let &preExp = buffer ""
        let &varDecls = buffer ""
        let &auxFunction = buffer ""
        let START = if init then crefOrStartCref(name, context, &preExp, &varDecls, &auxFunction) else cref(name, &sub)
        let PREV = if stringEq(&preExp, "") then "" else &preExp + "\n"
        let DECL = if stringEq(&varDecls, "") then "" else &varDecls + "\n"
        let AUX = if stringEq(&auxFunction, "") then "" else &auxFunction + "\n"
        '<%DECL%><%PREV%><%AUX%>data->simulationInfo->nonlinearSystemData[<%nls.indexNonLinearSystem%>].nlsxOld[<%i0%>] = <%START%>;'
      ;separator="\n"%>
      retValue = solve_nonlinear_system(data, threadData, <%nls.indexNonLinearSystem%>);
      /* check if solution process was successful */
      if (retValue > 0){
        const int indexes[2] = {1,<%nls.index%>};
        throwStreamPrintWithEquationIndexes(threadData, omc_dummyFileInfo, indexes, "Solving non-linear system <%nls.index%> failed at time=%.15g.\nFor more information please use -lv LOG_NLS.", data->localData[0]->timeValue);
        <%returnval2%>
      }
      /* write solution */
      <%nls.crefs |> name hasindex i0 =>
        let &sub = buffer ""
        '<%cref(name, &sub)%> = data->simulationInfo->nonlinearSystemData[<%nls.indexNonLinearSystem%>].nlsx[<%i0%>];' ;separator="\n"%>
      <% if profileSome() then 'SIM_PROF_ACC_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%nls.index%>).profileBlockIndex);' %>
      <%returnval%>
      >>
end equationNonlinear;

template equationNonlinearAlternativeTearing(SimEqSystem eq, Context context, String modelNamePrefix, Boolean init)
 "Generates a non linear equation system for the alternative tearing set."
::=
  match eq
    case eq as SES_NONLINEAR(nlSystem = nls as NONLINEARSYSTEM(__), alternativeTearing = SOME(at as NONLINEARSYSTEM(__))) then
      let size = listLength(at.crefs)
      let &tmp = buffer ""
      let innerBody = (at.eqs |> eq2 =>
         functionExtraResidualsPreBody(eq2, &tmp, modelNamePrefix)
       ;separator="\n")
      let nonlinindx = at.indexNonLinearSystem
      <<
      int retValue;
      if(ACTIVE_STREAM(LOG_DT))
      {
        infoStreamPrint(LOG_DT, 1, "Solving nonlinear system <%at.index%> (CASUAL TEARING SET, strict: <%nls.index%>) at time = %18.10e", data->localData[0]->timeValue);
        messageClose(LOG_DT);
      }
      <% if profileSome() then
      <<
      SIM_PROF_TICK_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%at.index%>).profileBlockIndex);
      SIM_PROF_ADD_NCALL_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%at.index%>).profileBlockIndex,-1);
      >>
      %>

      if (data->simulationInfo->nonlinearSystemData[<%at.indexNonLinearSystem%>].checkConstraints(data, threadData) == 1)
      {
        /* get old value */
        <%at.crefs |> name hasindex i0 =>
          let &sub = buffer ""
          let &preExp = buffer ""
          let &varDecls = buffer ""
          let &auxFunction = buffer ""
          let START = if init then crefOrStartCref(name, context, &preExp, &varDecls, &auxFunction) else cref(name, &sub)
          let PREV = if stringEq(&preExp, "") then "" else &preExp + "\n"
          let DECL = if stringEq(&varDecls, "") then "" else &varDecls + "\n"
          let AUX = if stringEq(&auxFunction, "") then "" else &auxFunction + "\n"
          '<%DECL%><%PREV%><%AUX%>data->simulationInfo->nonlinearSystemData[<%nls.indexNonLinearSystem%>].nlsxOld[<%i0%>] = <%START%>;'
        ;separator="\n"%>
        retValue = solve_nonlinear_system(data, threadData, <%at.indexNonLinearSystem%>);
        /* The casual tearing set found a solution */
        if (retValue == 0){
          /* write solution */
          <%at.crefs |> name hasindex i0 =>
            let &sub = buffer ""
            '<%cref(name, &sub)%> = data->simulationInfo->nonlinearSystemData[<%at.indexNonLinearSystem%>].nlsx[<%i0%>];' ;separator="\n"%>
          <% if profileSome() then 'SIM_PROF_ACC_EQ(modelInfoGetEquation(&data->modelData->modelDataXml,<%at.index%>).profileBlockIndex);' %>
        }
      }
      else
      {
        if(ACTIVE_STREAM(LOG_DT))
        {
          infoStreamPrint(LOG_DT, 1, "Constraints of the casual tearing set are violated! Now the strict tearing set is used.");
          messageClose(LOG_DT);
        }
        /* Global constraints are violated. Use the strict tearing set now. */
        data->simulationInfo->nonlinearSystemData[<%at.indexNonLinearSystem%>].strictTearingFunctionCall(data, threadData);
      }
      >>
end equationNonlinearAlternativeTearing;

template equationWhen(SimEqSystem eq, Context context, Text &varDecls, Text &auxFunction)
 "Generates a when equation."
::=
  match eq
    case SES_WHEN(whenStmtLst = whenStmtLst, conditions=conditions, elseWhen=NONE()) then
      let &sub = buffer ""
      let helpIf = if not listEmpty(conditions) then (conditions |> e => '(<%cref(e, &sub)%> && !<%crefPre(e)%> /* edge */)';separator=" || ") else '0'
      let assign = whenOperators(whenStmtLst, context, &varDecls, auxFunction)
      <<
      if(<%helpIf%>)
      {
        <%modelicaLine(eqInfo(eq))%>
        <%assign%>
        <%endModelicaLine()%>
      }
      >>
    case SES_WHEN(whenStmtLst = whenStmtLst, conditions=conditions, elseWhen=SOME(elseWhenEq)) then
      let &sub = buffer ""
      let helpIf = if not listEmpty(conditions) then (conditions |> e => '(<%cref(e, &sub)%> && !<%crefPre(e)%> /* edge */)';separator=" || ") else '0'
      let assign = whenOperators(whenStmtLst, context, &varDecls, auxFunction)
      let elseWhen = equationElseWhen(elseWhenEq,context,varDecls,&auxFunction)
      <<
      if(<%helpIf%>)
      {
        <%modelicaLine(eqInfo(eq))%>
        <%assign%>
        <%endModelicaLine()%>
      }
      <%elseWhen%>
      >>
end equationWhen;

template equationElseWhen(SimEqSystem eq, Context context, Text &varDecls, Text &auxFunction)
 "Generates a else when equation."
::=
let &sub = buffer ""
match eq
case SES_WHEN(whenStmtLst = whenStmtLst, conditions=conditions, elseWhen=NONE()) then
  let helpIf = (conditions |> e => '(<%cref(e, &sub)%> && !<%crefPre(e)%> /* edge */)';separator=" || ")
  let assign = whenOperators(whenStmtLst, context, &varDecls, auxFunction)

  if not listEmpty(conditions) then
    <<
    else if(<%helpIf%>)
    {
      <%modelicaLine(eqInfo(eq))%>
      <%assign%>
      <%endModelicaLine()%>
    }
    >>
case SES_WHEN(whenStmtLst = whenStmtLst, conditions=conditions, elseWhen=SOME(elseWhenEq)) then
  let helpIf = (conditions |> e => '(<%cref(e, &sub)%> && !<%crefPre(e)%> /* edge */)';separator=" || ")
  let assign = whenOperators(whenStmtLst, context, &varDecls, auxFunction)
  let elseWhen = equationElseWhen(elseWhenEq, context, varDecls, auxFunction)
  let body = if not listEmpty(conditions) then
    <<
    else if(<%helpIf%>)
    {
      <%modelicaLine(eqInfo(eq))%>
      <%assign%>
      <%endModelicaLine()%>
    }
    >>

  <<
  <%body%>
  <%elseWhen%>
  >>
end equationElseWhen;

template whenOperators(list<WhenOperator> whenOps, Context context, Text &varDecls, Text &auxFunction)
  "Generates body statements for when equation."
::=
  let body = (whenOps |> whenOp =>
    match whenOp
    case ASSIGN(left = lhs as DAE.CREF(componentRef=left)) then whenAssign(lhs, typeof(right), right, context, &varDecls, &auxFunction)
    case ASSIGN(left = lhs as DAE.TUPLE(PR = expLst as firstexp::_), right = DAE.CALL(attr=CALL_ATTR(ty=T_TUPLE(types=ntys)))) then
    let &preExp = buffer ""
    let &postExp = buffer ""
    let lhsCrefs = (List.rest(expLst) |> e => " ," + tupleReturnVariableUpdates(e, context, varDecls, preExp, postExp, &auxFunction))
    // The tuple expressions might take fewer variables than the number of outputs. No worries.
    let lhsCrefs2 = lhsCrefs + List.fill(", NULL", intMax(0,intSub(listLength(ntys),listLength(expLst))))
    let call = daeExpCallTuple(right, lhsCrefs2, context, &preExp, &varDecls, &auxFunction)
    let callassign = algStmtAssignWithRhsExpStr(firstexp, call, context, &preExp, &postExp, &varDecls, &auxFunction)
      <<
      <%preExp%>
      <%callassign%>
      <%postExp%>
      >>
    case REINIT(__) then
      let &sub = buffer ""
      let &preExp = buffer ""
      let val = daeExp(value, contextSimulationDiscrete, &preExp, &varDecls, &auxFunction)
      let lhs = match crefTypeConsiderSubs(stateVar)
         case DAE.T_ARRAY(__) then
           'copy_real_array_data_mem(<%val%>, &<%cref(stateVar, &sub)%>);'
         else
           '<%cref(stateVar, &sub)%> = <%val%>;'
      <<
      <%preExp%>
      <%lhs%>
      infoStreamPrint(LOG_EVENTS, 0, "reinit <%crefStrNoUnderscore(stateVar)%> = <%crefToPrintfArg(stateVar)%>", <%cref(stateVar, &sub)%>);
      data->simulationInfo->needToIterate = 1;
      >>
    case TERMINATE(__) then
      let &preExp = buffer ""
      let msgVar = daeExp(message, contextSimulationDiscrete, &preExp, &varDecls, &auxFunction)
      <<
      <%preExp%>
      FILE_INFO info = {<%infoArgs(getElementSourceFileInfo(source))%>};
      omc_terminate(info, MMC_STRINGDATA(<%msgVar%>));
      >>
    case ASSERT(source=SOURCE(info=info)) then
      assertCommon(condition, List.fill(message,1), level, contextSimulationDiscrete, &varDecls, &auxFunction, info)
    case NORETCALL(__) then
      let &preExp = buffer ""
      let expPart = daeExp(exp, contextSimulationDiscrete, &preExp, &varDecls, &auxFunction)
      <<
      <%preExp%>
      <% if isCIdentifier(expPart) then "" else '<%expPart%>;' %>
      >>
  ;separator="\n")
  <<
  <%body%>
  >>
end whenOperators;

template whenAssign(Exp left, Type ty, Exp right, Context context, Text &varDecls, Text &auxFunction)
 "Generates assignment for when."
::=
match ty
  case T_ARRAY(__) then
    let &preExp = buffer ""
    let expPart = daeExp(right, context, &preExp, &varDecls, &auxFunction)
    let assign = algStmtAssignArrWithRhsExpStr(left, expPart, context, &preExp, &varDecls, &auxFunction)
    <<
    <%preExp%>
    <%assign%>
    >>
  case T_COMPLEX(varLst = varLst, complexClassType=RECORD(__)) then
    error(sourceInfo(), 'No runtime support for this record assignment: <%dumpExp(left,"\"")%> = <%dumpExp(right,"\"")%>')
    // let &preExp = buffer ""
    // let exp = daeExp(right, context, &preExp, &varDecls, &auxFunction)
    // let tmp = tempDecl(expTypeModelica(ty),&varDecls)
    // <<
    // <%preExp%>
    // <%tmp%> = <%exp%>;
    // <% varLst |> var as TYPES_VAR(__) =>
    //   match var.ty
    //   case T_ARRAY(__) then
    //     copyArrayData(var.ty, '<%tmp%>._<%var.name%>', appendStringCref(var.name,left), context, &preExp, &varDecls, &auxFunction)
    //   else
    //     let varPart = contextCref(appendStringCref(var.name,left), context, &preExp, &varDecls, &auxFunction)
    //     '<%varPart%> = <%tmp%>._<%var.name%>;'
    // ; separator="\n"
    // %>
    // >>
  else
    let &preExp = buffer ""
    let varPart = daeExp(left, context, &preExp, &varDecls, &auxFunction)
    let exp = daeExp(right, context, &preExp, &varDecls, &auxFunction)
    <<
    <%preExp%>
    <%varPart%> = <%exp%>;
    >>
end whenAssign;

template equationIfEquationAssign(SimEqSystem eq, Context context, Text &varDecls, Text &eqnsDecls, String modelNamePrefixStr, Boolean init)
 "Generates a if equation."
::=
match eq
case SES_IFEQUATION(ifbranches=ifbranches, elsebranch=elsebranch) then
  let &preExp = buffer ""
  let IfEquation = (ifbranches |> (e, eqns) hasindex index0 =>
  let condition = daeExp(e, context, &preExp, &varDecls, &eqnsDecls)
  let &eqnsDecls += ( eqns |> eqn => equation_impl(-1, -1, eqn, context, modelNamePrefixStr, init) ; separator="\n" )
  let conditionline = if index0 then 'else if(<%condition%>)' else 'if(<%condition%>)'
    <<
    <%conditionline%>
    {
      <%( eqns |> eqn => equation_call_context(eqn, modelNamePrefixStr, context) ; separator="\n" )%>
    }
    >>
    ;separator="\n")
  let &eqnsDecls += ( elsebranch |> eqn => equation_impl(-1, -1, eqn, context, modelNamePrefixStr, init) ; separator="\n" )
  <<
  <%preExp%>
  <%IfEquation%>else
  {
    <%elsebranch |> eqn => equation_call_context(eqn, modelNamePrefixStr, context)%>
  }
  >>
end equationIfEquationAssign;

/* public */ template simulationLiteralsFile(String filePrefix, list<Exp> literals)
  "Generates the content of the C file for literals in the simulation case.
  used in Compiler/Template/CodegenFMU.tpl"
::=
  <<
  #ifdef __cplusplus
  extern "C" {
  #endif

  <%literals |> literal hasindex i0 fromindex 0 =>
    (if typeinfo() then '/* <%Util.escapeModelicaStringToCString(dumpExp(literal,"\""))%> */<%\n%>') +
    literalExpConst(literal,i0)
    ; separator="\n"; empty %>

  #ifdef __cplusplus
  }
  #endif<%\n%>
  >>
  /* adpro: leave a newline at the end of file to get rid of warnings! */
end simulationLiteralsFile;

/* public */ template simulationFunctionsFile(String filePrefix, list<Function> functions, list<SimGenericCall> genericCalls)
 "Generates the content of the C file for functions in the simulation case.
  used in Compiler/Template/CodegenFMU.tpl"
::=
  <<
  #include "omc_simulation_settings.h"
  #include "<%filePrefix%>_functions.h"
  #ifdef __cplusplus
  extern "C" {
  #endif

  #include "<%filePrefix%>_includes.h"

  <%if acceptParModelicaGrammar() then
  <<
  /* the OpenCL Kernels file name needed in libParModelicaExpl.a */
  const char* omc_ocl_kernels_source = "<%filePrefix%>_kernels.cl";
  /* the OpenCL program. Made global to avoid repeated builds */
  extern cl_program omc_ocl_program;
  /* The default OpenCL device. If not set (=0) show the selection option.*/
  unsigned int default_ocl_device = <%getDefaultOpenCLDevice()%>;
  >>
  %>

  <%functionBodies(functions,true)%>
  <%genericCallBodies(genericCalls, contextOther)%>

  #ifdef __cplusplus
  }
  #endif<%\n%>
  >>
  /* adpro: leave a newline at the end of file to get rid of warnings! */
end simulationFunctionsFile;

template simulationParModelicaKernelsFile(String filePrefix, list<Function> functions)
 "Generates the content of the C file for functions in the simulation case."
::=

  /* Reset the parfor loop id counter to 1*/
  let()= System.tmpTickResetIndex(0,20) /* parfor index */

  <<
  #include <ParModelica/explicit/openclrt/OCLRuntimeUtil.cl>

  // ParModelica Parallel Function headers.
  <%functionHeadersParModelica(filePrefix, functions)%>

  // Headers finish here.

  <%functionBodiesParModelica(functions)%>


  >>

end simulationParModelicaKernelsFile;

/* public */ template simulationFunctionsHeaderFile(String filePrefix, list<Function> functions, list<RecordDeclaration> recordDecls, list<SimGenericCall> genericCalls)
 "Generates the content of the C file for functions in the simulation case.
  used in Compiler/Template/CodegenFMU.tpl"
::=
  let &staticPrototypes = buffer ""
  <<
  #ifndef <%makeC89Identifier(filePrefix)%>__H
  #define <%makeC89Identifier(filePrefix)%>__H
  <%commonHeader(filePrefix)%>
  #include "simulation/simulation_runtime.h"
  #ifdef __cplusplus
  extern "C" {
  #endif
  <%\n%>
  <%recordDecls |> rd => recordDeclarationHeader(rd) ;separator="\n\n"%>
  <%\n%>
  <%functionHeaders(functions, true, staticPrototypes)%>
  <%genericCallHeaders(genericCalls, contextOther)%>
  #include "<%filePrefix%>_model.h"
  <%\n%>
  <%if staticPrototypes then
  <<
  /* default, do not make protected functions static */
  #if !defined(PROTECTED_FUNCTION_STATIC)
  #define PROTECTED_FUNCTION_STATIC
  #endif
  <%staticPrototypes%>
  >>
  %>
  <%\n%>
  #ifdef __cplusplus
  }
  #endif
  #endif<%\n%>
  <%\n%>
  >>
  /* adrpo: leave a newline at the end of file to get rid of the warning */
end simulationFunctionsHeaderFile;

template simulationMakefile(String target, SimCode simCode, list<String> extraFiles)
 "Generates the contents of the makefile for the simulation case."
::=
match getGeneralTarget(target)
case "msvc" then
match simCode
case SIMCODE(modelInfo=MODELINFO(__), makefileParams=MAKEFILE_PARAMS(__), simulationSettingsOpt = sopt) then
  let dirExtra = if modelInfo.directory then '/LIBPATH:"<%modelInfo.directory%>"' //else ""
  let libsStr = (makefileParams.libs |> lib => lib ;separator=" ")
  let libsPos1 = if not dirExtra then libsStr //else ""
  let libsPos2 = if dirExtra then libsStr // else ""
  let ParModelicaExpLibs = if acceptParModelicaGrammar() then 'ParModelicaExpl.lib OpenCL.lib' // else ""
  let extraCflags = match sopt case SOME(s as SIMULATION_SETTINGS(__)) then
    match s.method case "dassljac" then "-D_OMC_JACOBIAN "
  <<
  # Makefile generated by OpenModelica

  MODELICAUSERCFLAGS=
  CC=cl
  CXX=cl
  EXEEXT=.exe
  DLLEXT=.dll

  # /Od - Optimization disabled
  # /EHa enable C++ EH (w/ SEH exceptions)
  # /fp:except - consider floating-point exceptions when generating code
  # /arch:SSE2 - enable use of instructions available with SSE2 enabled CPUs
  # /I - Include Directories
  # /DNOMINMAX - Define NOMINMAX (does what it says)
  # /TP - Use C++ Compiler
  CFLAGS=/MP /Od /ZI /EHa /fp:except /I"<%makefileParams.omhome%>/include/omc/c" /I"<%makefileParams.omhome%>/include/omc/msvc/" /I. /DNOMINMAX /TP /DNO_INTERACTIVE_DEPENDENCY /DOPENMODELICA_XML_FROM_FILE_AT_RUNTIME <%if (Flags.isSet(Flags.HPCOM)) then '/openmp'%>
  # /ZI enable Edit and Continue debug info
  CDFLAGS=/ZI

  # /MD - link with MSVCRT.LIB
  # /link - [linker options and libraries]
  # /LIBPATH: - Directories where libs can be found
  LDFLAGS=/MD /link /NODEFAULTLIB:libcmt /STACK:0x2000000 /pdb:"<%fileNamePrefix%>.pdb" /LIBPATH:"<%makefileParams.omhome%>/lib/<%Autoconf.triple%>/omc/msvc/" /LIBPATH:"<%makefileParams.omhome%>/lib/<%Autoconf.triple%>/omc/msvc/release/" /LIBPATH:"<%makefileParams.omhome%>/lib/<%Autoconf.triple%>/omc/cpp/msvc/" <%dirExtra%> <%libsPos1%> <%libsPos2%> f2c.lib initialization.lib libexpat.lib math-support.lib meta.lib results.lib simulation.lib solver.lib sundials_kinsol.lib sundials_nvecserial.lib util.lib lapack_win32_MT.lib lis.lib  omcgc.lib user32.lib pthreadVC2.lib wsock32.lib cminpack.lib umfpack.lib amd.lib

  # /MDd link with MSVCRTD.LIB debug lib
  # lib names should not be appended with a d just switch to lib/omc/msvc/debug


  FILEPREFIX=<%fileNamePrefix%>
  MAINFILE=$(FILEPREFIX).c
  MAINOBJ=$(FILEPREFIX).obj
  CFILES=<%fileNamePrefix%>_functions.c <%fileNamePrefix%>_records.c \
  <%fileNamePrefix%>_01exo.c <%fileNamePrefix%>_02nls.c <%fileNamePrefix%>_03lsy.c <%fileNamePrefix%>_04set.c <%fileNamePrefix%>_05evt.c <%fileNamePrefix%>_06inz.c <%fileNamePrefix%>_07dly.c \
  <%fileNamePrefix%>_08bnd.c <%fileNamePrefix%>_09alg.c <%fileNamePrefix%>_10asr.c <%fileNamePrefix%>_11mix.c <%fileNamePrefix%>_12jac.c <%fileNamePrefix%>_13opt.c <%fileNamePrefix%>_14lnz.c \
  <%fileNamePrefix%>_15syn.c <%fileNamePrefix%>_16dae.c <%fileNamePrefix%>_17inl.c <%fileNamePrefix%>_18spd.c <%extraFiles |> extraFile => ' <%extraFile%>'%>

  OFILES=$(CFILES:.c=.obj)
  GENERATEDFILES=$(MAINFILE) $(FILEPREFIX)_functions.h $(FILEPREFIX).makefile $(CFILES)

  .PHONY: $(FILEPREFIX)$(EXEEXT)

  # This is to make sure that <%fileNamePrefix%>_*.c are always compiled.
  .PHONY: $(CFILES)

  $(FILEPREFIX)$(EXEEXT): $(MAINFILE) $(FILEPREFIX)_functions.h $(CFILES)
  <%\t%>$(CXX) /Fe$(FILEPREFIX)$(EXEEXT) $(MAINFILE) $(CFILES) $(CFLAGS) $(LDFLAGS)

  clean:
  <%\t%>rm -f *.obj *.lib *.exp *.c *.h *.xml *.libs *.log *.makefile *.pdb *.idb *.exe
  >>
end match
case "gcc" then
match simCode
case SIMCODE(modelInfo=MODELINFO(varInfo=varInfo as VARINFO(__)), delayedExps=DELAYED_EXPRESSIONS(maxDelayedIndex=maxDelayedIndex), makefileParams=MAKEFILE_PARAMS(__), simulationSettingsOpt = sopt) then
  let dirExtra = if modelInfo.directory then '-L"<%modelInfo.directory%>"' //else ""
  let libsStr = (makefileParams.libs |> lib => lib ;separator=" ")
  let libsPos1 = if not dirExtra then libsStr //else ""
  let libsPos2 = if dirExtra then libsStr // else ""
  let ParModelicaExpLibs = if acceptParModelicaGrammar() then '-lParModelicaExpl -lOpenCL' // else ""
  let ExtraStack = if boolOr(stringEq(makefileParams.platform, "win32"),stringEq(makefileParams.platform, "win64")) then '--stack,16777216,'
  let ExtraUnicodeFlag = if boolOr(stringEq(makefileParams.platform, "win32"),stringEq(makefileParams.platform, "win64")) then '-municode'
  let linkBinDirWindows = if boolOr(stringEq(makefileParams.platform, "win32"),stringEq(makefileParams.platform, "win64")) then '-L"<%makefileParams.omhome%>/bin"'
  let extraCflags = match sopt case SOME(s as SIMULATION_SETTINGS(__)) then
    match s.method case "dassljac" then "-D_OMC_JACOBIAN "

  <<
  # Makefile generated by OpenModelica
  # Platform: <%makefileParams.platform%>

  # Simulations use -O3 by default
  CC=<%if acceptParModelicaGrammar() then 'g++' else '<%makefileParams.ccompiler%>'%>
  CXX=<%makefileParams.cxxcompiler%>
  LINK=<%makefileParams.linker%>
  EXEEXT=<%makefileParams.exeext%>
  DLLEXT=<%makefileParams.dllext%>
  CFLAGS_BASED_ON_INIT_FILE=<%extraCflags%>
  # define OMC_CFLAGS_OPTIMIZATION env variable to your desired optimization level to override this
  OMC_CFLAGS_OPTIMIZATION=-Os
  DEBUG_FLAGS=<% if boolOr(Testsuite.isRunning(), boolOr(acceptMetaModelicaGrammar(), Flags.isSet(Flags.GEN_DEBUG_SYMBOLS))) then "-O0" else "$(OMC_CFLAGS_OPTIMIZATION)"%><% if Flags.isSet(Flags.GEN_DEBUG_SYMBOLS) then " -g" %>
  CFLAGS=<%ExtraUnicodeFlag%> $(CFLAGS_BASED_ON_INIT_FILE) $(DEBUG_FLAGS) <%makefileParams.cflags%> <%match sopt case SOME(s as SIMULATION_SETTINGS(__)) then '<%s.cflags%> ' /* From the simulate() command */%>
  <% if stringEq(Config.simCodeTarget(),"JavaScript") then 'OMC_EMCC_PRE_JS=<%makefileParams.omhome%>/lib/<%Autoconf.triple%>/omc/emcc/pre.js<%\n%>'
  %>CPPFLAGS=<%makefileParams.includes ; separator=" "%> -I"<%makefileParams.omhome%>/include/omc/c" -I"<%makefileParams.omhome%>/include/omc" -I. -DOPENMODELICA_XML_FROM_FILE_AT_RUNTIME<% if stringEq(Config.simCodeTarget(),"JavaScript") then " -DOMC_EMCC"%><% if Flags.isSet(Flags.OMC_RELOCATABLE_FUNCTIONS) then " -DOMC_GENERATE_RELOCATABLE_CODE"%> -DOMC_MODEL_PREFIX=<%modelNamePrefix(simCode)%> -DOMC_NUM_MIXED_SYSTEMS=<%varInfo.numMixedSystems%> -DOMC_NUM_LINEAR_SYSTEMS=<%varInfo.numLinearSystems%> -DOMC_NUM_NONLINEAR_SYSTEMS=<%varInfo.numNonLinearSystems%> -DOMC_NDELAY_EXPRESSIONS=<%maxDelayedIndex%> -DOMC_NVAR_STRING=<%varInfo.numStringAlgVars%>
  # define OMC_LDFLAGS_LINK_TYPE env variable to "static" to override this
  OMC_LDFLAGS_LINK_TYPE=dynamic
  RUNTIME_LIBS=<%makefileParams.runtimelibs%>
  LDFLAGS=<%
  if stringEq(Config.simCodeTarget(),"JavaScript") then <<-L'<%makefileParams.omhome%>/lib/<%Autoconf.triple%>/omc/emcc' -lblas -llapack -lexpat -lSimulationRuntimeC -s TOTAL_MEMORY=805306368 -s OUTLINING_LIMIT=20000 --pre-js $(OMC_EMCC_PRE_JS)>>
  else <<-L"<%makefileParams.omhome%>/lib/<%Autoconf.triple%>/omc" -L"<%makefileParams.omhome%>/lib" -Wl,<%ExtraStack%>-rpath,"<%makefileParams.omhome%>/lib/<%Autoconf.triple%>/omc" <%linkBinDirWindows%> -Wl,-rpath,"<%makefileParams.omhome%>/lib" <%ParModelicaExpLibs%> <%makefileParams.ldflags%> $(RUNTIME_LIBS) >>
  %>
  DIREXTRA=<%stringReplace(dirExtra,"#","\\#") /* make strips everything after # */%>
  MAINFILE=<%fileNamePrefix%>.c
  MAINOBJ=<%fileNamePrefix%>.o
  CFILES=<%fileNamePrefix%>_functions.c <%fileNamePrefix%>_records.c \
  <%fileNamePrefix%>_01exo.c <%fileNamePrefix%>_02nls.c <%fileNamePrefix%>_03lsy.c <%fileNamePrefix%>_04set.c <%fileNamePrefix%>_05evt.c <%fileNamePrefix%>_06inz.c <%fileNamePrefix%>_07dly.c \
  <%fileNamePrefix%>_08bnd.c <%fileNamePrefix%>_09alg.c <%fileNamePrefix%>_10asr.c <%fileNamePrefix%>_11mix.c <%fileNamePrefix%>_12jac.c <%fileNamePrefix%>_13opt.c <%fileNamePrefix%>_14lnz.c \
  <%fileNamePrefix%>_15syn.c <%fileNamePrefix%>_16dae.c <%fileNamePrefix%>_17inl.c <%fileNamePrefix%>_18spd.c <%extraFiles |> extraFile => ' \<%\n%>  <%extraFile%>'%>

  OFILES=$(CFILES:.c=.o)
  GENERATEDFILES=$(MAINFILE) <%fileNamePrefix%>.makefile <%fileNamePrefix%>_literals.h <%fileNamePrefix%>_functions.h $(CFILES)

  .PHONY: omc_main_target clean bundle

  # This is to make sure that <%fileNamePrefix%>_*.c are always compiled.
  .PHONY: $(CFILES)

  omc_main_target: $(MAINOBJ) <%fileNamePrefix%>_functions.h <%fileNamePrefix%>_literals.h $(OFILES)
  <%\t%><% if Flags.getConfigBool(Flags.PARMODAUTO) then '$(CXX)' else '$(CC)'%> -I. -o <%fileNamePrefix%>$(EXEEXT) $(MAINOBJ) $(OFILES) $(DIREXTRA) <%libsPos1%> <%libsPos2%> $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
  <% if stringEq(Config.simCodeTarget(),"JavaScript") then '<%\t%>rm -f <%fileNamePrefix%>'%>
  <% if stringEq(Config.simCodeTarget(),"JavaScript") then '<%\t%>ln -s <%fileNamePrefix%>_node.js <%fileNamePrefix%>'%>
  <% if stringEq(Config.simCodeTarget(),"JavaScript") then '<%\t%>chmod +x <%fileNamePrefix%>_node.js'%>

  omc_dll_target: $(MAINOBJ) <%fileNamePrefix%>_functions.h <%fileNamePrefix%>_literals.h $(OFILES)
  <%\t%>$(CC) -DOMC_DLL_MAIN_DEFINE -o $(MAINOBJ) -c $(MAINFILE) $(DIREXTRA) <%libsPos1%> <%libsPos2%> $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
  <%\t%><% if Flags.getConfigBool(Flags.PARMODAUTO) then '$(CXX)' else '$(CC)'%> -shared -I. -o <%fileNamePrefix%>$(DLLEXT) $(MAINOBJ) $(OFILES) $(DIREXTRA) <%libsPos1%> <%libsPos2%> $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)

  clean:
  <%\t%>@rm -f <%fileNamePrefix%>_records.o $(MAINOBJ)

  bundle:
  <%\t%>@tar -cvf <%fileNamePrefix%>_Files.tar $(GENERATEDFILES)
  >>
end match
else
  error(sourceInfo(), 'Target <%target%> is not handled!')
end simulationMakefile;

template crefM(ComponentRef cr)
 "Generates Modelica equivalent name for component reference."
::=
  match cr
  case CREF_IDENT(ident = "xloc") then crefStr(cr)
  case CREF_IDENT(ident = "time") then "time"
  else "P" + crefToMStr(cr)
end crefM;

template simEqAttrIsDiscreteKind(SimEqSystem eq)
::=
  match eq
  case SES_RESIDUAL(__)
  case SES_FOR_RESIDUAL(__)
  case SES_GENERIC_RESIDUAL(__)
  case SES_SIMPLE_ASSIGN(__)
  case SES_SIMPLE_ASSIGN_CONSTRAINTS(__)
  case SES_ARRAY_CALL_ASSIGN(__)
  case SES_GENERIC_ASSIGN(__)
  case SES_ENTWINED_ASSIGN(__)
  case SES_IFEQUATION(__)
  case SES_ALGORITHM(__)
  case SES_LINEAR(__)
  case SES_NONLINEAR(__)
  case SES_MIXED(__)
  case SES_WHEN(__)
  case SES_FOR_LOOP(__)
    then eqAttributeIsDiscreteKind(eqAttr)
  else ''
end simEqAttrIsDiscreteKind;

template eqAttributeIsDiscreteKind(EquationAttributes eqAtt)
::=
  match eqAtt
  case EQUATION_ATTRIBUTES(kind=kind) then '<%eqIsDiscreteKind(kind)%>'
  else ''
end eqAttributeIsDiscreteKind;

template eqIsDiscreteKind(EquationKind eqKind)
::=
  match eqKind
  case DISCRETE_EQUATION() then '1'
  else  '0'
end eqIsDiscreteKind;

template simEqAttrEval(SimEqSystem eq)
::=
  match eq
  case SES_RESIDUAL(__)
  case SES_FOR_RESIDUAL(__)
  case SES_GENERIC_RESIDUAL(__)
  case SES_SIMPLE_ASSIGN(__)
  case SES_SIMPLE_ASSIGN_CONSTRAINTS(__)
  case SES_ARRAY_CALL_ASSIGN(__)
  case SES_GENERIC_ASSIGN(__)
  case SES_ENTWINED_ASSIGN(__)
  case SES_IFEQUATION(__)
  case SES_ALGORITHM(__)
  case SES_LINEAR(__)
  case SES_NONLINEAR(__)
  case SES_MIXED(__)
  case SES_WHEN(__)
  case SES_FOR_LOOP(__)
    then eqAttributesEval(eqAttr)
  else ''
end simEqAttrEval;

template eqAttributesEval(EquationAttributes eqAtt)
::=
  match eqAtt
  case EQUATION_ATTRIBUTES(evalStages=evalStages) then '<%eqEval(evalStages)%>'
  else ''
end eqAttributesEval;

template eqEval(EvaluationStages eqEval)
::=
  match eqEval
  case EVALUATION_STAGES(__) then
    let dy = if dynamicEval then '+1' else ''
    let al = if algebraicEval then '+2' else ''
    let zc = if zerocrossEval then '+4' else ''
    let di = if discreteEval then '+8' else ''
  <<evalStages = 0<%dy%><%al%><%zc%><%di%>;>>
end eqEval;

/*****************************************************************************
 *         SECTION: GENERATE OPTIMIZATION IN SIMULATION FILE
 *****************************************************************************/

template optimizationComponents( list<DAE.ClassAttributes> classAttributes ,SimCode simCode, String modelNamePrefixStr)
  "Generates C for Objective Functions."
::=
    match classAttributes
    case{} then
        let fail = 'throwStreamPrint(NULL, "The model was not compiled with -g=Optimica and the corresponding goal function. The optimization solver cannot be used.");<%\n%>return 0;'
        <<
        int <%symbolName(modelNamePrefixStr,"mayer")%>(DATA* data, modelica_real** res,short *i) {
          <%fail%>
        }
        int <%symbolName(modelNamePrefixStr,"lagrange")%>(DATA* data, modelica_real** res, short * i1, short*i2) {
          <%fail%>
        }
        int <%symbolName(modelNamePrefixStr,"pickUpBoundsForInputsInOptimization")%>(DATA* data, modelica_real* min, modelica_real* max, modelica_real*nominal, modelica_boolean *useNominal, char ** name, modelica_real * start, modelica_real * startTimeOpt) {
          <%fail%>
        }
        int <%symbolName(modelNamePrefixStr,"setInputData")%>(DATA *data, const modelica_boolean file) {
          <%fail%>
        }
        int <%symbolName(modelNamePrefixStr,"getTimeGrid")%>(DATA *data, modelica_integer * nsi, modelica_real**t) {
          <%fail%>
        }
        >>
      else
        (classAttributes |> classAttribute => optimizationComponents1(classAttribute,simCode, modelNamePrefixStr); separator="\n")
end optimizationComponents;

template optimizationComponents1(ClassAttributes classAttribute, SimCode simCode, String modelNamePrefixStr)
"Generates C for class attributes of objective function."
::=
  match classAttribute
    case OPTIMIZATION_ATTRS(__) then
      let &sub = buffer ""
      let &varDecls = buffer ""
      let &preExp = buffer ""
      let &varDecls1 = buffer ""
      let &preExp1 = buffer ""
      let &auxFunction = buffer ""

      let objectiveFunction = match objetiveE
        case SOME(exp) then
          let setMayerIndex = if stringEq(crefToIndex(createDifferentiatedCrefName(makeUntypedCrefIdent(BackendDAE.optimizationMayerTermName), makeUntypedCrefIdent("dummyVarC"), "C")), "-2") then '' else
          <<
          *index_Dres = <%crefToIndex(createDifferentiatedCrefName(makeUntypedCrefIdent(BackendDAE.optimizationMayerTermName), makeUntypedCrefIdent("dummyVarC"), "C"))%>;
          return 0;
          >>
          <<
          *res =  &<%cref(makeUntypedCrefIdent(BackendDAE.optimizationMayerTermName), &sub)%>;
          <%setMayerIndex%>
          >>

      let startTimeOpt = match startTimeE
        case SOME(exp) then
          let startTimeOptExp = daeExp(exp, contextOther, &preExp, &varDecls, &auxFunction)
          <<
          *startTimeOpt = <%startTimeOptExp%>;
          >>

      let objectiveIntegrand = match objectiveIntegrandE
        case SOME(exp) then
          let setLagrangeIndex = if stringEq(crefToIndex(createDifferentiatedCrefName(makeUntypedCrefIdent(BackendDAE.optimizationLagrangeTermName), makeUntypedCrefIdent("dummyVarB"), "B")), "-2") then '' else
          <<
          *index_DresB = <%crefToIndex(createDifferentiatedCrefName(makeUntypedCrefIdent(BackendDAE.optimizationLagrangeTermName), makeUntypedCrefIdent("dummyVarB"), "B"))%>;
          *index_DresC = <%crefToIndex(createDifferentiatedCrefName(makeUntypedCrefIdent(BackendDAE.optimizationLagrangeTermName), makeUntypedCrefIdent("dummyVarC"), "C"))%>;
          return 0;
          >>
          <<
          *res =  &<%cref(makeUntypedCrefIdent(BackendDAE.optimizationLagrangeTermName), &sub)%>;
          <%setLagrangeIndex%>
          >>

      let setInput = match simCode
        case simCode as SIMCODE(__) then
          match modelInfo
            case MODELINFO(vars=SIMVARS(__)) then
            <<
              if(file){
              <%vars.inputVars |> SIMVAR(varKind = OPT_LOOP_INPUT(replaceExp=cr)) hasindex i0 =>
              '<%cref(name, &sub)%> = <%cref(cr, &sub)%> ;'
              ;separator="\n"
              %>
              }
              <%vars.inputVars |> SIMVAR(__) hasindex i0 =>
              'data->simulationInfo->inputVars[<%i0%>] = <%cref(name, &sub)%>;'
              ;separator="\n"
              %>
            >>

      let getTG = match simCode
        case simCode as SIMCODE(__) then
          match modelInfo
            case MODELINFO(vars=SIMVARS(__)) then
            <<
              *nsi=(-1 <%vars.paramVars |> SIMVAR(varKind=OPT_TGRID(__)) hasindex i0 => '+1'
               ;separator=" "%>);
              *t = (modelica_real*) malloc((*nsi+1)*sizeof(modelica_real));
              <%vars.paramVars |> SIMVAR(varKind=OPT_TGRID(__)) hasindex i0 =>
              '(*t)[<%i0%>] = <%cref(name, &sub)%>;'
              ;separator="\n"
              %>
            >>

      let inputBounds = match simCode
        case simCode as SIMCODE(__) then
          match modelInfo
            case MODELINFO(vars=SIMVARS(__)) then
              <<
              <%vars.inputVars |> SIMVAR(__) hasindex i0 =>
              'min[<%i0%>] = <%crefAttributes(name)%>.min;<%\n%>max[<%i0%>] = <%crefAttributes(name)%>.max;<%\n%>nominal[<%i0%>] = <%crefAttributes(name)%>.nominal;<%\n%>useNominal[<%i0%>] = <%crefAttributes(name)%>.useNominal;<%\n%>name[<%i0%>] =(char *) <%crefVarInfo(name)%>.name;<%\n%>start[<%i0%>] = <%crefAttributes(name)%>.start;'
              ;separator="\n"%>
              >>
           <<
           <%auxFunction%>
           /* objectiveFunction */
           int <%symbolName(modelNamePrefixStr,"mayer")%>(DATA* data, modelica_real** res, short * index_Dres)
           {
             <%varDecls%>
             <%preExp%>
             <%objectiveFunction%>
             return  -1;
           }
           /* objectiveIntegrand */
           int <%symbolName(modelNamePrefixStr,"lagrange")%>(DATA* data, modelica_real** res, short * index_DresB, short *index_DresC)
           {
             <%varDecls1%>
             <%preExp1%>
             <%objectiveIntegrand%>
             return -1;
           }

           /* opt vars  */
           int <%symbolName(modelNamePrefixStr,"pickUpBoundsForInputsInOptimization")%>(DATA* data, modelica_real* min, modelica_real* max, modelica_real*nominal, modelica_boolean *useNominal, char ** name, modelica_real * start, modelica_real* startTimeOpt)
           {
             <%inputBounds%>
             *startTimeOpt = data->simulationInfo->startTime - 1.0;
             <%startTimeOpt%>
             return 0;
           }

           int <%symbolName(modelNamePrefixStr,"setInputData")%>(DATA *data, const modelica_boolean file)
           {
            TRACE_PUSH
            <%setInput%>
            TRACE_POP
            return 0;
           }
           int <%symbolName(modelNamePrefixStr,"getTimeGrid")%>(DATA *data, modelica_integer * nsi, modelica_real**t){
            <%getTG%>
            return 0;
           }
           >>
    else error(sourceInfo(), 'Unknown Constraint List')
end optimizationComponents1;

template functionXXX_systemPartial(list<SimEqSystem> derivativEquations, String name, Integer n, String modelNamePrefixStr, ModelInfo modelInfo)
::=
    let code =  match modelInfo
    case MODELINFO(vars=SIMVARS(derivativeVars=ders)) then
    (ders |> SIMVAR(__) hasindex i0 => equationNames_Partial(SimCodeUtil.computeDependencies(derivativEquations,name),modelNamePrefixStr,i0,crefStr(name)) ; separator="\n")
<<
static void <%modelNamePrefixStr%>_function<%name%><%n%>(DATA *data, threadData_t *threadData, int i)
{
  switch (i) {
  <%code%>
  }
}
>>
end functionXXX_systemPartial;


template functionXXX_systemsPartial(list<list<SimEqSystem>> eqs, String name, Text &loop, Text &varDecls, String modelNamePrefixStr, ModelInfo modelInfo)
::=
  let funcs = (eqs |> eq hasindex i0 fromindex 0 => functionXXX_systemPartial(eq,name,i0,modelNamePrefixStr,modelInfo) ; separator="\n")
  match listLength(eqs)
  case 0 then //empty case
    let &loop +=
        <<
        /* no <%name%> systems */
        >>
    ""
  case 1 then //1 function
    let &loop +=
        <<
        <%modelNamePrefixStr%>_function<%name%>0(data, threadData,i);
        >>
    funcs //just the one function
  case nFuncs then //2 and more
    let funcNames = eqs |> e hasindex i0 fromindex 0 => 'function<%name%>_system<%i0%>' ; separator=",\n"
    let &varDecls += 'int id;<%\n%>'

    let &loop +=
      /* Text for the loop body that calls the equations */
      <<
      for(id=0; id<<%nFuncs%>; id++) {
        function<%name%>_systems[id](data, threadData);
      }
      >>
    /* Text before the function head */
    <<
    <%funcs%>
    static void (*function<%name%>_systems[<%nFuncs%>])(DATA *, threadData_t *threadData) = {
      <%funcNames%>
    };
    >>
end functionXXX_systemsPartial;

template equationNames_Partial(list<SimEqSystem> eqs, String modelNamePrefixStr, Integer i0, String cref_der)
 "Generates an equation.
  This template should not be used for a SES_RESIDUAL.
  Residual equations are handled differently."
::=
  let odeEqs = eqs |> eq => equationNames_(eq,contextSimulationNonDiscrete,modelNamePrefixStr); separator="\n"
  <<
  case <%i0%>:
    // Assigning <%cref_der%>
    <%odeEqs%>
    break;
  >>
end equationNames_Partial;

template genericCallBodies(list<SimGenericCall> genericCalls, Context context)
 "Generates the body for a set of generic calls."
::=
  let &sub = buffer ""
  let &preExp = buffer ""
  let &varDecls = buffer ""
  let &auxFunction = buffer ""
  let jac = match context case JACOBIAN_CONTEXT() then ", ANALYTIC_JACOBIAN *jacobian" else ""
  (genericCalls |> call => match call
    case SINGLE_GENERIC_CALL() then
      let lhs_ = daeExp(lhs, context, &preExp, &varDecls, &auxFunction)
      let rhs_ = daeExp(rhs, context, &preExp, &varDecls, &auxFunction)
      let iter_ = (iters |> iter => genericIterator(iter, context, &preExp, &varDecls, &auxFunction, &sub); separator = "\n")
      <<
      void genericCall_<%index%>(DATA *data, threadData_t *threadData<%jac%>, int idx)
      {
        int tmp = idx;
        <%iter_%>
        <%varDecls%>
        <%auxFunction%>
        <%preExp%>
        <%lhs_%> = <%rhs_%>;
      }
      >>
    case IF_GENERIC_CALL() then
      let iter_ = (iters |> iter => genericIterator(iter, context, &preExp, &varDecls, &auxFunction, &sub); separator = "\n")
      let branches_ = (branches |> branch => genericBranch(branch, context, &preExp, &varDecls, &auxFunction, &sub); separator = " else ")
      <<
      void genericCall_<%index%>(DATA *data, threadData_t *threadData<%jac%>, int idx)
      {
        int tmp = idx;
        <%iter_%>
        <%varDecls%>
        <%auxFunction%>
        <%preExp%>
        <%branches_%>
      }
      >>
    case WHEN_GENERIC_CALL() then
      let iter_ = (iters |> iter => genericIterator(iter, context, &preExp, &varDecls, &auxFunction, &sub); separator = "\n")
      let branches_ = (branches |> branch => genericBranch(branch, context, &preExp, &varDecls, &auxFunction, &sub); separator = " else ")
      <<
      void genericCall_<%index%>(DATA *data, threadData_t *threadData<%jac%>, int idx)
      {
        int tmp = idx;
        <%iter_%>
        <%varDecls%>
        <%auxFunction%>
        <%preExp%>
        <%branches_%>
      }
      >>
  ; separator="\n\n")
end genericCallBodies;

template genericBranch(SimBranch branch, Context context, Text &preExp, Text &varDecls, Text &auxFunction, Text &sub)
::= match branch
  case SIM_BRANCH() then
    let condition_ = match condition
      case SOME(cond) then <<if(<%daeExp(cond, context, &preExp, &varDecls, &auxFunction)%>)>>
      else ""
    let body_ = (body |> (lhs, rhs) =>
      <<<%daeExp(lhs, context, &preExp, &varDecls, &auxFunction)%> = <%daeExp(rhs, context, &preExp, &varDecls, &auxFunction)%>;>>
      ; separator="\n")
    <<
    <%condition_%>{
      <%body_%>
    }
    >>
  case SIM_BRANCH_STMT() then
    let condition_ = match condition
      case SOME(cond) then <<if(<%daeExp(cond, context, &preExp, &varDecls, &auxFunction)%>)>>
      else ""
    let body_ = (body |> stmt => algStatement(stmt, context, &varDecls, &auxFunction); separator="\n")
    <<
    <%condition_%>{
      <%body_%>
    }
    >>
end genericBranch;

template genericIterator(SimIterator iter, Context context, Text &preExp, Text &varDecls, Text &auxFunction, Text &sub)
::= match iter
  case SIM_ITERATOR() then
  let iter_ = contextCref(name, contextOther, &preExp, &varDecls, &auxFunction, &sub)
  <<
  int <%iter_%>_loc = tmp % <%size%>;
  int <%iter_%> = <%step%> * <%iter_%>_loc + <%start%>;
  tmp /= <%size%>;
  >>
end genericIterator;

template forIterator(SimIterator iter, Context context, Text &preExp, Text &varDecls, Text &auxFunction, Text &sub)
::= match iter
  case SIM_ITERATOR() then
  let iter_ = contextCref(name, contextOther, &preExp, &varDecls, &auxFunction, &sub)
  let rel = if intGt(step, 0) then "<" else ">"
  let sign = if intGt(step, 0) then "+" else "-"
  <<
  for(int <%iter_%>=<%start%>; <%iter_%><%rel%><%start%><%sign%><%size%>; <%iter_%>+=<%step%>){
  >>
end forIterator;

template forIteratorBody(SimIterator iter, Context context, Text &preExp, Text &varDecls, Text &auxFunction, Text &sub)
::= match iter
  case SIM_ITERATOR() then
  let iter_ = contextCref(name, contextOther, &preExp, &varDecls, &auxFunction, &sub)
  <<
  (<%iter_%>-<%start%>)/<%step%>+<%size%>*(
  >>
end forIteratorBody;

template genericCallHeaders(list<SimGenericCall> genericCalls, Context context)
 "Generates the header for a set of generic calls."
::=
  let jac = match context case JACOBIAN_CONTEXT() then ", ANALYTIC_JACOBIAN *jacobian" else ""
  (genericCalls |> call => match call
    case SINGLE_GENERIC_CALL() then <<void genericCall_<%index%>(DATA *data, threadData_t *threadData<%jac%>, int idx);>>
    case IF_GENERIC_CALL() then <<void genericCall_<%index%>(DATA *data, threadData_t *threadData<%jac%>, int idx);>>;
  separator="\n\n")
end genericCallHeaders;

annotation(__OpenModelica_Interface="backend");
end CodegenC;

// vim: filetype=susan sw=2 sts=2
